diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 2dddd3dea..03c833224 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -537,6 +537,18 @@ actors.hero.spells.guidinglight.name=guiding light actors.hero.spells.guidinglight.prompt=choose a target actors.hero.spells.guidinglight.desc=TODO, just deals damage atm +actors.hero.spells.holyward.name=holy ward +actors.hero.spells.holyward.glyph_name=%s of light +actors.hero.spells.holyward.glyph_desc=This glyph slightly increases the amount of damage armor can block. +actors.hero.spells.holyward.desc=TODO, temp armor buff + +actors.hero.spells.holyweapon.name=holy weapon +actors.hero.spells.holyweapon.ench_name=holy %s +actors.hero.spells.holyweapon.ench_desc=Enemies struck by a holy weapon will take extra magical damage. +actors.hero.spells.holyweapon.desc=TODO, temp melee weapon buff + + + ##main hero actors.hero.hero.name=you actors.hero.hero.leave=You can't leave yet, the rest of the dungeon awaits below! diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/HolyWard.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/HolyWard.java new file mode 100644 index 000000000..597d8a942 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/HolyWard.java @@ -0,0 +1,75 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2024 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +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.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; +import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.watabou.noosa.audio.Sample; + +public class HolyWard extends ClericSpell { + + public static HolyWard INSTANCE = new HolyWard(); + + @Override + public int icon() { + return HeroIcon.ENDURE; //TODO unique icon + } + + @Override + public float chargeUse(Hero hero) { + return 1; + } + + @Override + protected void activate(HolyTome tome, Hero hero, Integer target) { + + Buff.affect(hero, HolyArmBuff.class, 50f); + Item.updateQuickslot(); + + Sample.INSTANCE.play(Assets.Sounds.READ); + tome.spendCharge( 1f ); + hero.sprite.operate(hero.pos); + hero.spend( 1f ); + hero.next(); + } + + public static class HolyArmBuff extends FlavourBuff { + + @Override + public int icon() { + return BuffIndicator.ARMOR; + } + + @Override + public void detach() { + super.detach(); + Item.updateQuickslot(); + } + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/HolyWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/HolyWeapon.java new file mode 100644 index 000000000..3d42a1010 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/HolyWeapon.java @@ -0,0 +1,75 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2024 Evan Debenham + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see + */ + +package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +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.items.Item; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; +import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.watabou.noosa.audio.Sample; + +public class HolyWeapon extends ClericSpell { + + public static HolyWeapon INSTANCE = new HolyWeapon(); + + @Override + public int icon() { + return HeroIcon.ELEMENTAL_STRIKE; //TODO unique icon + } + + @Override + public float chargeUse(Hero hero) { + return 2; + } + + @Override + protected void activate(HolyTome tome, Hero hero, Integer target) { + + Buff.affect(hero, HolyWepBuff.class, 50f); + Item.updateQuickslot(); + + Sample.INSTANCE.play(Assets.Sounds.READ); + tome.spendCharge( 2f ); + hero.sprite.operate(hero.pos); + hero.spend( 1f ); + hero.next(); + } + + public static class HolyWepBuff extends FlavourBuff { + + @Override + public int icon() { + return BuffIndicator.WEAPON; + } + + @Override + public void detach() { + super.detach(); + Item.updateQuickslot(); + } + } + +} 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 0e14a25fd..981dd2942 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 @@ -32,6 +32,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Momentum; 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.actors.hero.spells.HolyWard; import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; import com.shatteredpixel.shatteredpixeldungeon.items.BrokenSeal; import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem; @@ -463,9 +464,14 @@ public class Armor extends EquipableItem { } public int proc( Char attacker, Char defender, int damage ) { - - if (glyph != null && defender.buff(MagicImmune.class) == null) { - damage = glyph.proc( this, attacker, defender, damage ); + + if (defender.buff(MagicImmune.class) == null) { + if (defender instanceof Hero && isEquipped((Hero) defender) + && !hasCurseGlyph() && defender.buff(HolyWard.HolyArmBuff.class) != null){ + damage -= 1; + } else if (glyph != null) { + damage = glyph.proc( this, attacker, defender, damage ); + } } if (!levelKnown && defender == Dungeon.hero) { @@ -500,7 +506,11 @@ public class Armor extends EquipableItem { @Override public String name() { - return glyph != null && (cursedKnown || !glyph.curse()) ? glyph.name( super.name() ) : super.name(); + if (isEquipped(Dungeon.hero) && !hasCurseGlyph() && Dungeon.hero.buff(HolyWard.HolyArmBuff.class) != null){ + return Messages.get(HolyWard.class, "glyph_name", super.name()); + } else { + return glyph != null && (cursedKnown || !glyph.curse()) ? glyph.name( super.name() ) : super.name(); + } } @Override @@ -531,8 +541,11 @@ public class Armor extends EquipableItem { break; case NONE: } - - if (glyph != null && (cursedKnown || !glyph.curse())) { + + if (isEquipped(Dungeon.hero) && !hasCurseGlyph() && Dungeon.hero.buff(HolyWard.HolyArmBuff.class) != null){ + info += "\n\n" + Messages.capitalize(Messages.get(Armor.class, "inscribed", Messages.get(HolyWard.class, "glyph_name", Messages.get(Glyph.class, "glyph")))); + info += " " + Messages.get(HolyWard.class, "glyph_desc"); + } else if (glyph != null && (cursedKnown || !glyph.curse())) { info += "\n\n" + Messages.capitalize(Messages.get(Armor.class, "inscribed", glyph.name())); if (glyphHardened) info += " " + Messages.get(Armor.class, "glyph_hardened"); info += " " + glyph.desc(); @@ -677,10 +690,16 @@ public class Armor extends EquipableItem { public boolean hasCurseGlyph(){ return glyph != null && glyph.curse(); } - + + private static ItemSprite.Glowing HOLY = new ItemSprite.Glowing( 0xFFFF00 ); + @Override public ItemSprite.Glowing glowing() { - return glyph != null && (cursedKnown || !glyph.curse()) ? glyph.glowing() : null; + if (isEquipped(Dungeon.hero) && !hasCurseGlyph() && Dungeon.hero.buff(HolyWard.HolyArmBuff.class) != null){ + return HOLY; + } else { + return glyph != null && (cursedKnown || !glyph.curse()) ? glyph.glowing() : null; + } } public static abstract class Glyph implements Bundlable { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/AntiMagic.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/AntiMagic.java index 2c5e4cc18..3fd6e01a0 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/AntiMagic.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/armor/glyphs/AntiMagic.java @@ -32,6 +32,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.El import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.ElementalBlast; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WarpBeacon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.GuidingLight; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalWisp; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM100; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Eye; @@ -90,6 +91,7 @@ public class AntiMagic extends Armor.Glyph { RESISTS.add( HolyDart.class ); RESISTS.add( GuidingLight.class ); + RESISTS.add( HolyWeapon.class ); RESISTS.add( ElementalBlast.class ); RESISTS.add( CursedWand.class ); 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 780eee145..3c90a4c59 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 @@ -29,6 +29,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicImmune; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.ElementalStrike; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon; import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; @@ -113,9 +114,14 @@ abstract public class Weapon extends KindOfWeapon { @Override public int proc( Char attacker, Char defender, int damage ) { - - if (enchantment != null && attacker.buff(MagicImmune.class) == null) { - damage = enchantment.proc( this, attacker, defender, damage ); + + if (attacker.buff(MagicImmune.class) == null) { + if (attacker instanceof Hero && isEquipped((Hero) attacker) + && !hasCurseEnchant() && attacker.buff(HolyWeapon.HolyWepBuff.class) != null){ + defender.damage(2, HolyWeapon.INSTANCE); + } else if (enchantment != null) { + damage = enchantment.proc(this, attacker, defender, damage); + } } if (!levelKnown && attacker == Dungeon.hero) { @@ -327,7 +333,11 @@ abstract public class Weapon extends KindOfWeapon { @Override public String name() { - return enchantment != null && (cursedKnown || !enchantment.curse()) ? enchantment.name( super.name() ) : super.name(); + if (isEquipped(Dungeon.hero) && !hasCurseEnchant() && Dungeon.hero.buff(HolyWeapon.HolyWepBuff.class) != null){ + return Messages.get(HolyWeapon.class, "ench_name", super.name()); + } else { + return enchantment != null && (cursedKnown || !enchantment.curse()) ? enchantment.name(super.name()) : super.name(); + } } @Override @@ -383,7 +393,13 @@ abstract public class Weapon extends KindOfWeapon { } public boolean hasEnchant(Class type, Char owner) { - return enchantment != null && enchantment.getClass() == type && owner.buff(MagicImmune.class) == null; + if (owner.buff(MagicImmune.class) != null) { + return false; + } else if (owner instanceof Hero && isEquipped((Hero) owner) && owner.buff(HolyWeapon.HolyWepBuff.class) != null){ + return false; + } else { + return enchantment != null && enchantment.getClass() == type; + } } //these are not used to process specific enchant effects, so magic immune doesn't affect them @@ -395,9 +411,15 @@ abstract public class Weapon extends KindOfWeapon { return enchantment != null && enchantment.curse(); } + private static ItemSprite.Glowing HOLY = new ItemSprite.Glowing( 0xFFFF00 ); + @Override public ItemSprite.Glowing glowing() { - return enchantment != null && (cursedKnown || !enchantment.curse()) ? enchantment.glowing() : null; + if (isEquipped(Dungeon.hero) && !hasCurseEnchant() && Dungeon.hero.buff(HolyWeapon.HolyWepBuff.class) != null){ + return HOLY; + } else { + return enchantment != null && (cursedKnown || !enchantment.curse()) ? enchantment.glowing() : null; + } } public static abstract class Enchantment implements Bundlable { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java index 9fcdd15bd..99f939787 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/weapon/melee/MeleeWeapon.java @@ -35,6 +35,7 @@ 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.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon; @@ -335,7 +336,10 @@ public class MeleeWeapon extends Weapon { case NONE: } - if (enchantment != null && (cursedKnown || !enchantment.curse())){ + if (isEquipped(Dungeon.hero) && !hasCurseEnchant() && Dungeon.hero.buff(HolyWeapon.HolyWepBuff.class) != null){ + info += "\n\n" + Messages.capitalize(Messages.get(Weapon.class, "enchanted", Messages.get(HolyWeapon.class, "ench_name", Messages.get(Enchantment.class, "enchant")))); + info += " " + Messages.get(HolyWeapon.class, "ench_desc"); + } else if (enchantment != null && (cursedKnown || !enchantment.curse())){ info += "\n\n" + Messages.capitalize(Messages.get(Weapon.class, "enchanted", enchantment.name())); if (enchantHardened) info += " " + Messages.get(Weapon.class, "enchant_hardened"); info += " " + enchantment.desc(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndClericSpells.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndClericSpells.java index 38dbd0732..5c2393223 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndClericSpells.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/windows/WndClericSpells.java @@ -26,6 +26,8 @@ import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.ClericSpell; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.GuidingLight; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWard; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene; @@ -69,6 +71,8 @@ public class WndClericSpells extends Window { //TODO build spell list ArrayList spells = new ArrayList<>(); spells.add(GuidingLight.INSTANCE); + spells.add(HolyWeapon.INSTANCE); + spells.add(HolyWard.INSTANCE); ArrayList spellBtns = new ArrayList<>();