v3.0.0: implemented the remaining cleric T1 talents/spells

This commit is contained in:
Evan Debenham
2024-10-25 17:10:34 -04:00
parent 3cf13f0458
commit 2827f0ee96
14 changed files with 174 additions and 26 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -533,6 +533,7 @@ actors.hero.abilities.ratmogrify$transmograt.desc=This enemy has been transforme
actors.hero.abilities.ratmogrify$transmograt.rankings_desc=Slain by: ratmogrified enemy
##Cleric Spells
actors.hero.spells.clericspell.no_target=There is no target there.
actors.hero.spells.clericspell.charge_cost=Charge cost: %d
actors.hero.spells.detectcurse.name=detect curse
@@ -543,7 +544,7 @@ actors.hero.spells.detectcurse.short_desc=identifies whether an item is cursed o
actors.hero.spells.detectcurse.desc=The Cleric focuses their senses on an item and determines whether it is cursed or not without having to equip it.
actors.hero.spells.guidinglight.name=guiding light
actors.hero.spells.guidinglight.prompt=choose a target
actors.hero.spells.guidinglight.prompt=Choose a target
actors.hero.spells.guidinglight.short_desc=Deals ranged magic damage and guarantees a hit.
actors.hero.spells.guidinglight.desc=The Cleric fires a bolt of magical energy which strikes a target, dealing 2-6 damage and illuminating them. The next physical attack made against an illuminated enemy is guaranteed to hit them.
@@ -563,7 +564,12 @@ actors.hero.spells.holyweapon.desc=The Cleric enchants their worn weapon with ho
actors.hero.spells.holyweapon$holywepbuff.name=holy weapon
actors.hero.spells.holyweapon$holywepbuff.desc=The Cleric has imbued their worn weapon with holy energy, temporarily overriding any existing enchantment and causing the weapon to deal an extra 2 magical damage on each attack.\n\nTurn renaming: %s.
actors.hero.spells.shieldoflight.name=shield of light
actors.hero.spells.shieldoflight.prompt=Choose a target
actors.hero.spells.shieldoflight.short_desc=Grants temporary armor against a target.
actors.hero.spells.shieldoflight.desc=The Cleric creates a thin barrier of light between themselves and an enemy, increasing their armor's block power against that enemy by 2-4 for %d turns.\n\nThis spell takes no time to cast, but cannot be used against multiple targets simultaneously.
actors.hero.spells.shieldoflight$shieldoflighttracker.name=shield of light
actors.hero.spells.shieldoflight$shieldoflighttracker.desc=A thin shield of light is standing between the Cleric and an enemy. It's not strong enough to outright block attacks, but will soften them.\n\nTurns Remaining: %s
##main hero
actors.hero.hero.name=you
@@ -674,6 +680,8 @@ actors.hero.talent$preciseassaulttracker.desc=The Duelist's next regular melee a
actors.hero.talent$deadlyfollowuptracker.name=deadly followup
actors.hero.talent$deadlyfollowuptracker.desc=The Duelist has recently attacked an enemy with a thrown weapon, her melee attacks against the same target will have boosted damage.\n\nTurns remaining: %s.
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.
#warrior
actors.hero.talent.hearty_meal.title=hearty meal
@@ -994,16 +1002,16 @@ actors.hero.talent.counter_ability.title=counter ability
actors.hero.talent.counter_ability.desc=_+1:_ If the Duelist uses a weapon ability within 3 turns of her afterimage being attacked, she will instantly regain _0.38 charges_.\n\n_+2:_ If the Duelist uses a weapon ability within 3 turns of her afterimage being attacked, she will instantly regain _0.77 charges_.\n\n_+3:_ If the Duelist uses a weapon ability within 3 turns of her afterimage being attacked, she will instantly regain _1.13 charges_.\n\n_+4:_ If the Duelist uses a weapon ability within 3 turns of her afterimage being attacked, she will instantly regain _1.5 charges_.
#cleric
actors.hero.talent.clerict1a.title=fasting
actors.hero.talent.clerict1a.desc=_+1:_ The Cleric can cast _???_ at the cost of 1 charge. This spell restores _30 turns of satiety_, grants _3 shielding_, and is cast instantly.\n\n_+2:_ The Cleric can cast _???_ at the cost of 1 charge. This spell restores _50 turns of satiety_, grants _5 shielding_, and is cast instantly.
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.detect_curse.title=detect curse
actors.hero.talent.detect_curse.desc=_+1:_ The Cleric can cast _Detect Curse,_ a spell that reveals whether an item is cursed at the cost of _3 charges._\n\n_+2:_ The Cleric can cast _Detect Curse,_ a spell that reveals whether an item is cursed at the cost of _2 charges._
actors.hero.talent.searing_light.title=searing light
actors.hero.talent.searing_light.desc=_+1:_ Physical attacks on enemies illuminated by _Guiding Light_ deal _+3 damage._\n\n_+2:_ Physical attacks on enemies illuminated by _Guiding Light_ deal _+5 damage._
actors.hero.talent.clerict1d.title=circle of healing
actors.hero.talent.clerict1d.desc=_+1:_ The Cleric can cast _Circle of Healing_ at the cost of 2 charges. This spell surrounds the Cleric in a healing aura, restoring 1 HP per turn for _10 turns_ to the Cleric and anything adjacent to them.\n\n_+2:_ The Cleric can cast _Circle of Healing_ at the cost of 2 charges. This spell surrounds the Cleric in a healing aura, restoring 1 HP per turn for _15 turns_ to the Cleric and anything adjacent to them.
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 _3 turns_ at the cost of 1 charge.\n\n_+2:_ The Cleric can cast _Shield of Light,_ a spell that is cast instantly and them 2-4 armor against a target for _5 turns_ at the cost of 1 charge.
actors.hero.talent.clerict2a.title=TODO
actors.hero.talent.clerict2a.title=Enlightening Meal
actors.hero.talent.clerict2a.desc=TODO
actors.hero.talent.clerict2b.title=TODO
actors.hero.talent.clerict2b.desc=TODO

View File

@@ -80,6 +80,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Challenge;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.DeathMark;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.Endure;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.ShieldOfLight;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Brute;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalSpire;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DwarfKing;
@@ -652,6 +653,11 @@ public abstract class Char extends Actor {
damage = armor.absorb( damage );
}
ShieldOfLight.ShieldOfLightTracker shield = buff( ShieldOfLight.ShieldOfLightTracker.class);
if (shield != null && shield.object == enemy.id()){
damage -= Random.NormalIntRange(2, 4);
}
return damage;
}

View File

@@ -172,7 +172,7 @@ public enum Talent {
FEIGNED_RETREAT(151, 4), EXPOSE_WEAKNESS(152, 4), COUNTER_ABILITY(153, 4),
//Cleric T1
CLERICT1A(160), DETECT_CURSE(161), SEARING_LIGHT(162), CLERICT1D(163),
SATIATED_SPELLS(160), DETECT_CURSE(161), SEARING_LIGHT(162), SHIELD_OF_LIGHT(163),
//Cleric T2
CLERICT2A(164), CLERICT2B(165), CLERICT2C(166), CLERICT2D(167), CLERICT2E(168),
//Cleric T3
@@ -389,6 +389,12 @@ public enum Talent {
}
}
public static class CounterAbilityTacker extends FlavourBuff{};
public static class SatiatedSpellsTracker extends Buff{
@Override
public int icon() {
return BuffIndicator.SPELL_FOOD;
}
};
int icon;
int maxPoints;
@@ -579,6 +585,9 @@ public enum Talent {
Buff.affect( hero, PhysicalEmpower.class).set(Math.round(hero.lvl / (4f - hero.pointsInTalent(FOCUSED_MEAL))), 1);
}
}
if (hero.hasTalent(SATIATED_SPELLS)){
Buff.affect( hero, SatiatedSpellsTracker.class );
}
}
public static class WarriorFoodImmunity extends FlavourBuff{
@@ -869,7 +878,7 @@ public enum Talent {
Collections.addAll(tierTalents, STRENGTHENING_MEAL, ADVENTURERS_INTUITION, PATIENT_STRIKE, AGGRESSIVE_BARRIER);
break;
case CLERIC:
Collections.addAll(tierTalents, CLERICT1A, DETECT_CURSE, SEARING_LIGHT, CLERICT1D);
Collections.addAll(tierTalents, SATIATED_SPELLS, DETECT_CURSE, SEARING_LIGHT, SHIELD_OF_LIGHT);
break;
}
for (Talent talent : tierTalents){

View File

@@ -22,6 +22,9 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier;
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.items.artifacts.HolyTome;
@@ -32,7 +35,7 @@ import java.util.ArrayList;
public abstract class ClericSpell {
public abstract void onCast(HolyTome tome, Hero hero );
public abstract void onCast(HolyTome tome, Hero hero);
public float chargeUse( Hero hero ){
return 1;
@@ -54,6 +57,15 @@ public abstract class ClericSpell {
return HeroIcon.NONE;
}
public void onSpellCast(HolyTome tome, Hero hero){
Invisibility.dispel();
if (hero.hasTalent(Talent.SATIATED_SPELLS) && hero.buff(Talent.SatiatedSpellsTracker.class) != null){
Buff.affect(hero, Barrier.class).setShield(1 + 2*hero.pointsInTalent(Talent.SATIATED_SPELLS));
hero.buff(Talent.SatiatedSpellsTracker.class).detach();
}
tome.spendCharge(chargeUse(hero));
}
public static ArrayList<ClericSpell> getSpellList(Hero cleric){
ArrayList<ClericSpell> spells = new ArrayList<>();
@@ -61,6 +73,10 @@ public abstract class ClericSpell {
spells.add(HolyWeapon.INSTANCE);
spells.add(HolyWard.INSTANCE);
if (cleric.hasTalent(Talent.SHIELD_OF_LIGHT)){
spells.add(ShieldOfLight.INSTANCE);
}
if (cleric.hasTalent(Talent.DETECT_CURSE)){
spells.add(DetectCurse.INSTANCE);
}

View File

@@ -22,7 +22,6 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
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.items.EquipableItem;
@@ -70,10 +69,8 @@ public class DetectCurse extends InventoryClericSpell {
hero.busy();
hero.sprite.operate(hero.pos);
tome.spendCharge(chargeUse(hero));
Sample.INSTANCE.play( Assets.Sounds.SCAN );
Invisibility.dispel();
onSpellCast(tome, hero);
}

View File

@@ -25,7 +25,6 @@ import com.shatteredpixel.shatteredpixeldungeon.Assets;
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.Invisibility;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
@@ -64,7 +63,7 @@ public class GuidingLight extends TargetedClericSpell {
hero.busy();
Sample.INSTANCE.play( Assets.Sounds.ZAP );
hero.sprite.zap(target);
MagicMissile.boltFromChar(hero.sprite.parent, MagicMissile.BEACON, hero.sprite, aim.collisionPos, new Callback() {
MagicMissile.boltFromChar(hero.sprite.parent, MagicMissile.MAGIC_MISSILE, hero.sprite, aim.collisionPos, new Callback() {
@Override
public void call() {
@@ -77,11 +76,11 @@ public class GuidingLight extends TargetedClericSpell {
}
}
tome.spendCharge( chargeUse(hero) );
hero.spend( 1f );
hero.next();
Invisibility.dispel();
onSpellCast(tome, hero);
}
});
}

View File

@@ -24,7 +24,6 @@ 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.buffs.Invisibility;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
@@ -48,13 +47,12 @@ public class HolyWard extends ClericSpell {
Item.updateQuickslot();
Sample.INSTANCE.play(Assets.Sounds.READ);
tome.spendCharge( chargeUse(hero) );
hero.spend( 1f );
hero.busy();
hero.sprite.operate(hero.pos);
Invisibility.dispel();
onSpellCast(tome, hero);
}
public static class HolyArmBuff extends FlavourBuff {

View File

@@ -24,7 +24,6 @@ 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.buffs.Invisibility;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
@@ -53,14 +52,12 @@ public class HolyWeapon extends ClericSpell {
Item.updateQuickslot();
Sample.INSTANCE.play(Assets.Sounds.READ);
tome.spendCharge( chargeUse(hero) );
hero.sprite.operate(hero.pos);
hero.spend( 1f );
hero.busy();
hero.sprite.operate(hero.pos);
Invisibility.dispel();
onSpellCast(tome, hero);
}
public static class HolyWepBuff extends FlavourBuff {

View File

@@ -0,0 +1,115 @@
/*
* 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 <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.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Bundle;
public class ShieldOfLight extends TargetedClericSpell {
public static ShieldOfLight INSTANCE = new ShieldOfLight();
@Override
public int icon() {
return HeroIcon.SHIELD_OF_LIGHT;
}
@Override
protected void onTargetSelected(HolyTome tome, Hero hero, Integer target) {
if (target == null){
return;
}
Char ch = Actor.findChar(target);
if (ch == null || ch.alignment == Char.Alignment.ALLY){
GLog.w(Messages.get(this, "no_target"));
return;
}
Sample.INSTANCE.play(Assets.Sounds.READ);
hero.sprite.operate(hero.pos);
//1 turn less as the casting is instant
Buff.affect( hero, ShieldOfLightTracker.class, 2f*hero.pointsInTalent(Talent.SHIELD_OF_LIGHT)).object = ch.id();
hero.busy();
hero.sprite.operate(hero.pos);
onSpellCast(tome, hero);
}
@Override
public String desc() {
return Messages.get(this, "desc", 1+2*Dungeon.hero.pointsInTalent(Talent.SHIELD_OF_LIGHT)) + "\n\n" + Messages.get(this, "charge_cost", (int)chargeUse(Dungeon.hero));
}
public static class ShieldOfLightTracker extends FlavourBuff {
public int object = 0;
{
type = buffType.POSITIVE;
}
@Override
public int icon() {
return BuffIndicator.LIGHT_SHIELD;
}
@Override
public float iconFadePercent() {
float duration = 1f + 2f* Dungeon.hero.pointsInTalent(Talent.SHIELD_OF_LIGHT);
return Math.max(0, (duration - visualcooldown()) / duration);
}
private static final String OBJECT = "object";
@Override
public void storeInBundle( Bundle bundle ) {
super.storeInBundle( bundle );
bundle.put( OBJECT, object );
}
@Override
public void restoreFromBundle( Bundle bundle ) {
super.restoreFromBundle( bundle );
object = bundle.getInt( OBJECT );
}
}
}

View File

@@ -124,6 +124,8 @@ public class BuffIndicator extends Component {
public static final int WAND = 72;
public static final int HOLY_WEAPON = 73;
public static final int HOLY_ARMOR = 74;
public static final int SPELL_FOOD = 75;
public static final int LIGHT_SHIELD= 76;
public static final int SIZE_SMALL = 7;
public static final int SIZE_LARGE = 16;

View File

@@ -71,7 +71,8 @@ public class HeroIcon extends Image {
public static final int GUIDING_LIGHT = 40;
public static final int HOLY_WEAPON = 41;
public static final int HOLY_WARD = 42;
public static final int DETECT_CURSE = 43;
public static final int SHIELD_OF_LIGHT = 43;
public static final int DETECT_CURSE = 44;
//action indicator visuals
public static final int BERSERK = 80;