From 3c963e917f86ac9e4e77b8003b21f23dc1dda3a6 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Mon, 3 Feb 2025 16:39:23 -0500 Subject: [PATCH] v3.0.0: fully implemented body form's effect --- core/src/main/assets/interfaces/buffs.png | Bin 1836 -> 1846 bytes .../main/assets/interfaces/large_buffs.png | Bin 4132 -> 4161 bytes .../assets/messages/actors/actors.properties | 17 +-- .../actors/hero/Hero.java | 36 +++++-- .../actors/hero/abilities/cleric/Trinity.java | 101 ++++++++++++++++-- .../actors/hero/spells/BodyForm.java | 74 +++++++++++++ .../items/armor/Armor.java | 16 +++ .../items/weapon/Weapon.java | 29 ++++- .../ui/BuffIndicator.java | 1 + 9 files changed, 246 insertions(+), 28 deletions(-) diff --git a/core/src/main/assets/interfaces/buffs.png b/core/src/main/assets/interfaces/buffs.png index 5b50844486b303aad4ae5b74e71ab6f79374a53d..59b3120ca196f09a0a41e400def7e98b34412733 100644 GIT binary patch delta 1488 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 cls) { if (belongings.armor() != null && belongings.armor().hasGlyph(cls, this)){ return Math.max(super.glyphLevel(cls), belongings.armor.buffedLvl()); + } else if (buff(BodyForm.BodyFormBuff.class) != null + && buff(BodyForm.BodyFormBuff.class).glyph() != null + && buff(BodyForm.BodyFormBuff.class).glyph().getClass() == cls){ + return belongings.armor() != null ? belongings.armor.buffedLvl() : 0; } else { return super.glyphLevel(cls); } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java index e32dd2e8f..b102362de 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/Trinity.java @@ -24,6 +24,8 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric; import com.shatteredpixel.shatteredpixeldungeon.Assets; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Statistics; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility; @@ -77,14 +79,14 @@ public class Trinity extends ArmorAbility { if (bodyForm == null && mindForm == null && spiritForm == null){ GLog.w(Messages.get(this, "no_imbue")); } else { - GameScene.show(new WndUseTrinity()); + GameScene.show(new WndUseTrinity(armor)); } } public class WndUseTrinity extends WndTitledMessage { - public WndUseTrinity() { + public WndUseTrinity(ClassArmor armor) { super(new HeroIcon(Trinity.this), Messages.titleCase(Trinity.this.name()), Messages.get(WndUseTrinity.class, "text")); @@ -100,26 +102,74 @@ public class Trinity extends ArmorAbility { + " " + trinityItemUseText(bodyForm.getClass()), 6){ @Override protected void onClick() { - //TODO + if (Dungeon.hero.belongings.weapon() != null && + ((Weapon)Dungeon.hero.belongings.weapon()).enchantment.getClass().equals(bodyForm.getClass())){ + GLog.w(Messages.get(Trinity.class, "no_duplicate")); + hide(); + } else { + Buff.affect(Dungeon.hero, BodyForm.BodyFormBuff.class, BodyForm.duration()).setEffect(bodyForm); + Sample.INSTANCE.play(Assets.Sounds.TELEPORT); + Weapon w = new WornShortsword(); + if (Dungeon.hero.belongings.weapon() != null) { + w.image = Dungeon.hero.belongings.weapon().image; + } + w.enchant((Weapon.Enchantment) bodyForm); + Enchanting.show(Dungeon.hero, w); + Dungeon.hero.sprite.operate(Dungeon.hero.pos); + Dungeon.hero.spendAndNext(1f); + armor.charge -= trinityChargeUsePerEffect(bodyForm.getClass()); + armor.updateQuickslot(); + Invisibility.dispel(); + hide(); + } } }; - btnBody.icon(new ItemSprite(ItemSpriteSheet.WORN_SHORTSWORD, ((Weapon.Enchantment) bodyForm).glowing())); + if (Dungeon.hero.belongings.weapon() != null) { + btnBody.icon(new ItemSprite(Dungeon.hero.belongings.weapon().image, ((Weapon.Enchantment) bodyForm).glowing())); + } else { + btnBody.icon(new ItemSprite(ItemSpriteSheet.WORN_SHORTSWORD, ((Weapon.Enchantment) bodyForm).glowing())); + } } else if (bodyForm instanceof Armor.Glyph){ btnBody = new RedButton(Messages.get(WndUseTrinity.class, "body", Messages.titleCase(((Armor.Glyph)bodyForm).name())) + " " + trinityItemUseText(bodyForm.getClass()), 6){ @Override protected void onClick() { - //TODO + if (Dungeon.hero.belongings.armor() != null && + (Dungeon.hero.belongings.armor()).glyph.getClass().equals(bodyForm.getClass())){ + GLog.w(Messages.get(Trinity.class, "no_duplicate")); + hide(); + } else { + Buff.affect(Dungeon.hero, BodyForm.BodyFormBuff.class, BodyForm.duration()).setEffect(bodyForm); + Sample.INSTANCE.play(Assets.Sounds.TELEPORT); + Armor a = new ClothArmor(); + if (Dungeon.hero.belongings.armor() != null) { + a.image = Dungeon.hero.belongings.armor().image; + } + a.inscribe((Armor.Glyph) bodyForm); + Enchanting.show(Dungeon.hero, a); + Dungeon.hero.sprite.operate(Dungeon.hero.pos); + Dungeon.hero.spendAndNext(1f); + armor.charge -= trinityChargeUsePerEffect(bodyForm.getClass()); + armor.updateQuickslot(); + Invisibility.dispel(); + hide(); + } } }; - btnBody.icon(new ItemSprite(ItemSpriteSheet.ARMOR_CLOTH, ((Armor.Glyph) bodyForm).glowing())); + if (Dungeon.hero.belongings.armor() != null) { + btnBody.icon(new ItemSprite(Dungeon.hero.belongings.armor().image, ((Armor.Glyph) bodyForm).glowing())); + } else { + btnBody.icon(new ItemSprite(ItemSpriteSheet.ARMOR_CLOTH, ((Armor.Glyph) bodyForm).glowing())); + } } btnBody.multiline = true; btnBody.setSize(width, 100); //for text layout btnBody.setRect(0, top + 2, width, btnBody.reqHeight()); add(btnBody); top = (int)btnBody.bottom(); + + btnBody.enable(armor.charge >= trinityChargeUsePerEffect(bodyForm.getClass())); } if (mindForm != null){ @@ -145,6 +195,12 @@ public class Trinity extends ArmorAbility { + " " + trinityItemUseText(spiritForm.getClass()), 6){ @Override protected void onClick() { + if (Dungeon.hero.belongings.ring().getClass().equals(spiritForm.getClass()) + || Dungeon.hero.belongings.misc().getClass().equals(spiritForm.getClass()) + || Dungeon.hero.belongings.artifact().getClass().equals(spiritForm.getClass())){ + GLog.w(Messages.get(Trinity.class, "no_duplicate")); + hide(); + } //TODO } }; @@ -241,10 +297,16 @@ public class Trinity extends ArmorAbility { for (Class cls : discoveredClasses){ if (Weapon.Enchantment.class.isAssignableFrom(cls)){ MeleeWeapon w = new WornShortsword(); + if (Dungeon.hero.belongings.weapon() != null){ + w.image = Dungeon.hero.belongings.weapon().image; + } w.enchant((Weapon.Enchantment) Reflection.newInstance(cls)); options.add(w); } else if (Armor.Glyph.class.isAssignableFrom(cls)) { Armor a = new ClothArmor(); + if (Dungeon.hero.belongings.armor() != null){ + a.image = Dungeon.hero.belongings.armor().image; + } a.inscribe((Armor.Glyph) Reflection.newInstance(cls)); options.add(a); } else { @@ -349,16 +411,16 @@ public class Trinity extends ArmorAbility { } public static String trinityItemUseText(Class cls ){ - float chargeUse = Dungeon.hero.armorAbility.chargeUse(Dungeon.hero); + float chargeUse = trinityChargeUsePerEffect(cls); if (Weapon.Enchantment.class.isAssignableFrom(cls) || Armor.Glyph.class.isAssignableFrom(cls)) { for (Class ench : Weapon.Enchantment.rare) { if (ench.equals(cls)) { - return Messages.get(Trinity.class, "rare_ench_glyph_use", BodyForm.duration(), Messages.decimalFormat("#.##", 2*chargeUse)); + return Messages.get(Trinity.class, "rare_ench_glyph_use", BodyForm.duration(), Messages.decimalFormat("#.##", chargeUse)); } } for (Class glyph : Armor.Glyph.rare){ if (glyph.equals(cls)){ - return Messages.get(Trinity.class, "rare_ench_glyph_use", BodyForm.duration(), Messages.decimalFormat("#.##", 2*chargeUse)); + return Messages.get(Trinity.class, "rare_ench_glyph_use", BodyForm.duration(), Messages.decimalFormat("#.##", chargeUse)); } } return Messages.get(Trinity.class, "ench_glyph_use", BodyForm.duration(), Messages.decimalFormat("#.##", chargeUse)); @@ -379,4 +441,25 @@ public class Trinity extends ArmorAbility { } + public static float trinityChargeUsePerEffect(Class cls){ + float chargeUse = Dungeon.hero.armorAbility.chargeUse(Dungeon.hero); + if (Weapon.Enchantment.class.isAssignableFrom(cls) || Armor.Glyph.class.isAssignableFrom(cls)) { + for (Class ench : Weapon.Enchantment.rare) { + if (ench.equals(cls)) { + return 2*chargeUse; + } + } + for (Class glyph : Armor.Glyph.rare){ + if (glyph.equals(cls)){ + return 2*chargeUse; + } + } + } + if (Artifact.class.isAssignableFrom(cls)){ + return chargeUse; //TODO + } + //all other effects are standard charge use + return chargeUse; + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/BodyForm.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/BodyForm.java index e051cf329..d653ffb62 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/BodyForm.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/BodyForm.java @@ -22,12 +22,20 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +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.Trinity; +import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; +import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.watabou.noosa.Image; +import com.watabou.utils.Bundlable; +import com.watabou.utils.Bundle; public class BodyForm extends ClericSpell { @@ -59,4 +67,70 @@ public class BodyForm extends ClericSpell { return Math.round(13.33f + 6.67f* Dungeon.hero.pointsInTalent(Talent.BODY_FORM)); } + public static class BodyFormBuff extends FlavourBuff { + + { + type = buffType.POSITIVE; + } + + private Bundlable effect; + + @Override + public int icon() { + return BuffIndicator.TRINITY_FORM; + } + + @Override + public void tintIcon(Image icon) { + icon.hardlight(1, 0, 0); + } + + @Override + public float iconFadePercent() { + return Math.max(0, (duration() - visualcooldown()) / duration()); + } + + public void setEffect(Bundlable effect){ + this.effect = effect; + } + + public Weapon.Enchantment enchant(){ + if (effect instanceof Weapon.Enchantment){ + return (Weapon.Enchantment) effect; + } + return null; + } + + public Armor.Glyph glyph(){ + if (effect instanceof Armor.Glyph){ + return (Armor.Glyph) effect; + } + return null; + } + + @Override + public String desc() { + if (enchant() != null){ + return Messages.get(this, "desc", Messages.titleCase(enchant().name()), dispTurns()); + } else if (glyph() != null){ + return Messages.get(this, "desc", Messages.titleCase(glyph().name()), dispTurns()); + } + return super.desc(); + } + + private static final String EFFECT = "effect"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(EFFECT, effect); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + effect = bundle.get(EFFECT); + } + } + } 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 187761d2c..c8db53d57 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 @@ -34,6 +34,7 @@ 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.AuraOfProtection; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.BodyForm; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWard; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal; @@ -434,18 +435,33 @@ public class Armor extends EquipableItem { public int proc( Char attacker, Char defender, int damage ) { if (defender.buff(MagicImmune.class) == null) { + Glyph trinityGlyph = null; + if (Dungeon.hero.buff(BodyForm.BodyFormBuff.class) != null){ + trinityGlyph = Dungeon.hero.buff(BodyForm.BodyFormBuff.class).glyph(); + if (glyph != null && trinityGlyph != null && trinityGlyph.getClass() == glyph.getClass()){ + trinityGlyph = null; + } + } + if (defender instanceof Hero && isEquipped((Hero) defender) && defender.buff(HolyWard.HolyArmBuff.class) != null){ if (glyph != null && (((Hero) defender).subClass == HeroSubClass.PALADIN || hasCurseGlyph())){ damage = glyph.proc( this, attacker, defender, damage ); } + if (trinityGlyph != null){ + damage = trinityGlyph.proc( this, attacker, defender, damage ); + } int blocking = ((Hero) defender).subClass == HeroSubClass.PALADIN ? 3 : 1; damage -= Math.round(blocking * Glyph.genericProcChanceMultiplier(defender)); + } else { if (glyph != null) { damage = glyph.proc(this, attacker, defender, damage); } + if (trinityGlyph != null){ + damage = trinityGlyph.proc( this, attacker, defender, damage ); + } //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 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java index 987ef3782..0e81b88d1 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/Weapon.java @@ -32,6 +32,7 @@ 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.duelist.ElementalStrike; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.BodyForm; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.Smite; import com.shatteredpixel.shatteredpixeldungeon.items.Item; @@ -122,6 +123,15 @@ abstract public class Weapon extends KindOfWeapon { boolean becameAlly = false; boolean wasAlly = defender.alignment == Char.Alignment.ALLY; if (attacker.buff(MagicImmune.class) == null) { + //TODO body form + Enchantment trinityEnchant = null; + if (Dungeon.hero.buff(BodyForm.BodyFormBuff.class) != null){ + trinityEnchant = Dungeon.hero.buff(BodyForm.BodyFormBuff.class).enchant(); + if (enchantment != null && trinityEnchant != null && trinityEnchant.getClass() == enchantment.getClass()){ + trinityEnchant = null; + } + } + if (attacker instanceof Hero && isEquipped((Hero) attacker) && attacker.buff(HolyWeapon.HolyWepBuff.class) != null){ if (enchantment != null && @@ -131,16 +141,27 @@ abstract public class Weapon extends KindOfWeapon { becameAlly = true; } } + if (defender.isAlive() && !becameAlly && trinityEnchant != null){ + damage = trinityEnchant.proc(this, attacker, defender, damage); + } if (defender.isAlive() && !becameAlly) { int dmg = ((Hero) attacker).subClass == HeroSubClass.PALADIN ? 6 : 2; defender.damage(Math.round(dmg * Enchantment.genericProcChanceMultiplier(attacker)), HolyWeapon.INSTANCE); } - } else if (enchantment != null) { - damage = enchantment.proc(this, attacker, defender, damage); - if (defender.alignment == Char.Alignment.ALLY && !wasAlly){ - becameAlly = true; + + } else { + if (enchantment != null) { + damage = enchantment.proc(this, attacker, defender, damage); + if (defender.alignment == Char.Alignment.ALLY && !wasAlly) { + becameAlly = true; + } + } + + if (defender.isAlive() && !becameAlly && trinityEnchant != null){ + damage = trinityEnchant.proc(this, attacker, defender, damage); } } + if (attacker instanceof Hero && isEquipped((Hero) attacker) && attacker.buff(Smite.SmiteTracker.class) != null && !becameAlly){ defender.damage(Smite.bonusDmg((Hero) attacker, defender), Smite.INSTANCE); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java index 63982801c..646975644 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java @@ -131,6 +131,7 @@ public class BuffIndicator extends Component { public static final int ASCEND = 79; public static final int PROT_AURA = 80; public static final int ILLUMINATED = 81; + public static final int TRINITY_FORM= 82; public static final int SIZE_SMALL = 7; public static final int SIZE_LARGE = 16;