v3.0.0: implemented the Paladin's smite spell

This commit is contained in:
Evan Debenham
2025-01-14 14:45:29 -05:00
parent 02bbe17a0b
commit 5570e015fd
9 changed files with 143 additions and 7 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -579,6 +579,7 @@ actors.hero.spells.cleanse.desc=The Cleric instantly clears all harmful effects
actors.hero.spells.clericspell.prompt=Choose a target actors.hero.spells.clericspell.prompt=Choose a target
actors.hero.spells.clericspell.no_target=There is no target there. actors.hero.spells.clericspell.no_target=There is no target there.
actors.hero.spells.clericspell.invalid_target=You can't target that location. actors.hero.spells.clericspell.invalid_target=You can't target that location.
actors.hero.spells.clericspell.invalid_enemy=You can't target that enemy.
actors.hero.spells.clericspell.charge_cost=Charge cost: %d actors.hero.spells.clericspell.charge_cost=Charge cost: %d
actors.hero.spells.divinesense.name=divine sense actors.hero.spells.divinesense.name=divine sense
@@ -632,7 +633,6 @@ actors.hero.spells.holyward$holyarmbuff.name=holy ward
actors.hero.spells.holyward$holyarmbuff.desc=The Cleric has imbued their worn armor with holy energy, temporarily overriding any existing glyph and causing the armor to block an extra 1 point of damage.\n\nTurns Remaining: %s. actors.hero.spells.holyward$holyarmbuff.desc=The Cleric has imbued their worn armor with holy energy, temporarily overriding any existing glyph and causing the armor to block an extra 1 point of damage.\n\nTurns Remaining: %s.
actors.hero.spells.holyward$holyarmbuff.desc_paladin=The Paladin has imbued their worn armor with holy energy, causing the armor to block an extra 3 points of damage.\n\nCasting other spells while holy ward is active will extend its duration by 10 turns per charge spent.\n\nTurns Remaining: %s. actors.hero.spells.holyward$holyarmbuff.desc_paladin=The Paladin has imbued their worn armor with holy energy, causing the armor to block an extra 3 points of damage.\n\nCasting other spells while holy ward is active will extend its duration by 10 turns per charge spent.\n\nTurns Remaining: %s.
actors.hero.spells.holyweapon.name=holy weapon actors.hero.spells.holyweapon.name=holy weapon
actors.hero.spells.holyweapon.ench_name=holy %s 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.ench_desc=Enemies struck by a holy weapon will take extra magical damage.
@@ -675,6 +675,10 @@ actors.hero.spells.spiritform.name=spirit form
actors.hero.spells.spiritform.short_desc=TODO actors.hero.spells.spiritform.short_desc=TODO
actors.hero.spells.spiritform.desc=TODO actors.hero.spells.spiritform.desc=TODO
actors.hero.spells.smite.name=smite
actors.hero.spells.smite.short_desc=Guarantees a hit with bonus damage and enchant power.
actors.hero.spells.smite.desc=The Paladin infuses a melee strike with righteous destructive power.\n\nIn addition to dealing normal melee damage, smite is guaranteed to hit, has +300%% enchantment power, and deals %1$d - %2$d bonus magic damage.\n\nSmite's bonus magic damage scales with the Paladin's level, and it will always deal maximum bonus magic damage against undead or demonic foes.
actors.hero.spells.sunray.name=sunray actors.hero.spells.sunray.name=sunray
actors.hero.spells.sunray.short_desc=Deals ranged magic damage and blinds a target once. actors.hero.spells.sunray.short_desc=Deals ranged magic damage and blinds a target once.
actors.hero.spells.sunray.desc=The Cleric fires a ray of blinding light at a target, dealing %1$d-%2$d damage and blinding them for %3$d turns. Sunray always deals maximum damage to undead and demonic targets.\n\nAfter being struck with this spell an enemy's vision will adjust, preventing them from being blinded by it again. However, if they are struck again while blinded by this spell, then the light is overwhelming and paralyses them instead. actors.hero.spells.sunray.desc=The Cleric fires a ray of blinding light at a target, dealing %1$d-%2$d damage and blinding them for %3$d turns. Sunray always deals maximum damage to undead and demonic targets.\n\nAfter being struck with this spell an enemy's vision will adjust, preventing them from being blinded by it again. However, if they are struck again while blinded by this spell, then the light is overwhelming and paralyses them instead.

View File

@@ -74,6 +74,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.En
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HallowedGround; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HallowedGround;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWard; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWard;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.Smite;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk;
@@ -1454,6 +1455,10 @@ public class Hero extends Char {
int dmg = subClass == HeroSubClass.PALADIN ? 6 : 2; int dmg = subClass == HeroSubClass.PALADIN ? 6 : 2;
enemy.damage(Math.round(dmg * Weapon.Enchantment.genericProcChanceMultiplier(this)), HolyWeapon.INSTANCE); enemy.damage(Math.round(dmg * Weapon.Enchantment.genericProcChanceMultiplier(this)), HolyWeapon.INSTANCE);
} }
if (buff(Smite.SmiteTracker.class) != null){
enemy.damage(Smite.bonusDmg(this, enemy), Smite.INSTANCE);
}
switch (subClass) { switch (subClass) {
case SNIPER: case SNIPER:

View File

@@ -135,8 +135,7 @@ public abstract class ClericSpell {
spells.add(Radiance.INSTANCE); spells.add(Radiance.INSTANCE);
} else if (cleric.subClass == HeroSubClass.PALADIN){ } else if (cleric.subClass == HeroSubClass.PALADIN){
//TODO innate smite spell spells.add(Smite.INSTANCE);
} }
if (cleric.hasTalent(Talent.CLEANSE)){ if (cleric.hasTalent(Talent.CLEANSE)){
@@ -146,15 +145,15 @@ public abstract class ClericSpell {
if (cleric.hasTalent(Talent.HOLY_LANCE)){ if (cleric.hasTalent(Talent.HOLY_LANCE)){
spells.add(HolyLance.INSTANCE); spells.add(HolyLance.INSTANCE);
} }
if (cleric.hasTalent(Talent.HALLOWED_GROUND)){ if (cleric.hasTalent(Talent.HALLOWED_GROUND)){
spells.add(HallowedGround.INSTANCE); spells.add(HallowedGround.INSTANCE);
} }
if (cleric.hasTalent(Talent.MNEMONIC_PRAYER)){ if (cleric.hasTalent(Talent.MNEMONIC_PRAYER)){
spells.add(MnemonicPrayer.INSTANCE); spells.add(MnemonicPrayer.INSTANCE);
} }
//TODO paladin spells
} else if (tier == 4){ } else if (tier == 4){
if (cleric.hasTalent(Talent.DIVINE_INTERVENTION)){ if (cleric.hasTalent(Talent.DIVINE_INTERVENTION)){

View File

@@ -0,0 +1,114 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2025 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 <http://www.gnu.org/licenses/>
*/
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
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.buffs.Invisibility;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.AttackIndicator;
import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Callback;
import com.watabou.utils.Random;
public class Smite extends TargetedClericSpell {
public static Smite INSTANCE = new Smite();
@Override
public int icon() {
return HeroIcon.SMITE;
}
@Override
public String desc() {
int min = 5 + Dungeon.hero.lvl/2;
int max = 10 + Dungeon.hero.lvl;
return Messages.get(this, "desc", min, max) + "\n\n" + Messages.get(this, "charge_cost", (int)chargeUse(Dungeon.hero));
}
@Override
public float chargeUse(Hero hero) {
return 2f;
}
@Override
protected void onTargetSelected(HolyTome tome, Hero hero, Integer target) {
if (target == null) {
return;
}
Char enemy = Actor.findChar(target);
if (enemy == null || enemy == hero){
GLog.w(Messages.get(this, "no_target"));
return;
}
//we apply here because of projecting
SmiteTracker tracker = Buff.affect(hero, SmiteTracker.class);
if (hero.isCharmedBy(enemy) || !Dungeon.level.heroFOV[target] || !hero.canAttack(enemy)) {
GLog.w(Messages.get(this, "invalid_enemy"));
tracker.detach();
return;
}
hero.sprite.attack(enemy.pos, new Callback() {
@Override
public void call() {
AttackIndicator.target(enemy);
if (hero.attack(enemy, 1, 0, Char.INFINITE_ACCURACY)){
Sample.INSTANCE.play(Assets.Sounds.HIT_STRONG);
enemy.sprite.burst(0xFFFFFFFF, 10);
}
tracker.detach();
Invisibility.dispel();
hero.spendAndNext(hero.attackDelay());
onSpellCast(tome, hero);
}
});
}
public static int bonusDmg( Hero attacker, Char defender){
int min = 5 + attacker.lvl/2;
int max = 10 + attacker.lvl;
if (Char.hasProp(defender, Char.Property.UNDEAD) || Char.hasProp(defender, Char.Property.DEMONIC)){
return max;
} else {
return Random.NormalIntRange(min, max);
}
}
public static class SmiteTracker extends FlavourBuff {};
}

View File

@@ -35,6 +35,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WarpB
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.GuidingLight; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.GuidingLight;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyLance; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyLance;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.Smite;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.Sunray; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.Sunray;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalWisp; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalWisp;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM100; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM100;
@@ -97,6 +98,7 @@ public class AntiMagic extends Armor.Glyph {
RESISTS.add( HolyWeapon.class ); RESISTS.add( HolyWeapon.class );
RESISTS.add( Sunray.class ); RESISTS.add( Sunray.class );
RESISTS.add( HolyLance.class ); RESISTS.add( HolyLance.class );
RESISTS.add( Smite.class );
RESISTS.add( Judgement.class ); RESISTS.add( Judgement.class );
RESISTS.add( ElementalBlast.class ); RESISTS.add( ElementalBlast.class );

View File

@@ -32,6 +32,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.AscendedForm; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.AscendedForm;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.ElementalStrike; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.ElementalStrike;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HolyWeapon;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.Smite;
import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon; import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon;
import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag; import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag;
@@ -130,6 +131,10 @@ abstract public class Weapon extends KindOfWeapon {
} else if (enchantment != null) { } else if (enchantment != null) {
damage = enchantment.proc(this, attacker, defender, damage); damage = enchantment.proc(this, attacker, defender, damage);
} }
if (attacker instanceof Hero && isEquipped((Hero) attacker) &&
attacker.buff(Smite.SmiteTracker.class) != null){
defender.damage(Smite.bonusDmg((Hero) attacker, defender), Smite.INSTANCE);
}
} }
if (!levelKnown && attacker == Dungeon.hero) { if (!levelKnown && attacker == Dungeon.hero) {
@@ -488,6 +493,10 @@ abstract public class Weapon extends KindOfWeapon {
attacker.buff(RunicBlade.RunicSlashTracker.class).detach(); attacker.buff(RunicBlade.RunicSlashTracker.class).detach();
} }
if (attacker.buff(Smite.SmiteTracker.class) != null){
multi += 3f;
}
if (attacker.buff(ElementalStrike.DirectedPowerTracker.class) != null){ if (attacker.buff(ElementalStrike.DirectedPowerTracker.class) != null){
multi += attacker.buff(ElementalStrike.DirectedPowerTracker.class).enchBoost; multi += attacker.buff(ElementalStrike.DirectedPowerTracker.class).enchBoost;
attacker.buff(ElementalStrike.DirectedPowerTracker.class).detach(); attacker.buff(ElementalStrike.DirectedPowerTracker.class).detach();

View File

@@ -35,7 +35,7 @@ public class HeroIcon extends Image {
private static final int SIZE = 16; private static final int SIZE = 16;
//transparent icon //transparent icon
public static final int NONE = 63; public static final int NONE = 127;
//subclasses //subclasses
public static final int BERSERKER = 0; public static final int BERSERKER = 0;
@@ -87,7 +87,10 @@ public class HeroIcon extends Image {
public static final int HOLY_LANCE = 51; public static final int HOLY_LANCE = 51;
public static final int HALLOWED_GROUND = 52; public static final int HALLOWED_GROUND = 52;
public static final int MNEMONIC_PRAYER = 53; public static final int MNEMONIC_PRAYER = 53;
//Paladin spells go here public static final int SMITE = 54;
public static final int LAY_ON_HANDS = 55;
//56
//57
public static final int DIVINE_INTERVENTION = 58; public static final int DIVINE_INTERVENTION = 58;
public static final int JUDGEMENT = 59; public static final int JUDGEMENT = 59;
public static final int FLASH = 60; public static final int FLASH = 60;