v3.0.0: lots of polish to initial Cleric spells

This commit is contained in:
Evan Debenham
2024-10-18 14:43:11 -04:00
parent dcbf989eba
commit c7b144a720
13 changed files with 118 additions and 53 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: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@@ -535,17 +535,21 @@ actors.hero.abilities.ratmogrify$transmograt.rankings_desc=Slain by: ratmogrifie
##Cleric Spells
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.guidinglight.desc=The Cleric files a bolt of magical energy which strikes a target, dealing 2-6 damage and illuminating them. The next melee attack made against an illuminated enemy is guaranteed to hit them.\n\nThis spell costs 1 charge.
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.holyward.desc=The Cleric imbues their worn armor with glyphs of holy light, increasing the armor's damage blocking by 1.\n\nThis glyph lasts for 50 turns, and will override any beneficial glyph the armor has for the duration.\n\nThis spell costs 1 charge.
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\nTurn renaming: %s.
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
actors.hero.spells.holyweapon.desc=The Cleric enchants their worn weapon with holy energy, causing the weapon to deal an additional 2 magical damage any time they strike an enemy with it.\n\nThis enchantment lasts for 50 turns, and will override any beneficial enchantment the weapon has for the duration.\n\nThis spell costs 2 charges.
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.

View File

@@ -39,6 +39,11 @@ windows.wndchoosesubclass.no=No, I'll decide later.
windows.wndclass.mastery=Mastery
windows.wndclericspells.cast_title=cast a spell
windows.wndclericspells.info_title=spell info
windows.wndclericspells.cast_desc=Select a spell to cast it, or press the info button to switch to info mode.
windows.wndclericspells.info_desc=Select a spell to learn about it, or press the info button to switch to cast mode.
windows.wndcombo.title=choose a combo move
windows.wndcombo.combo_req=(%d combo)

View File

@@ -44,7 +44,7 @@ public class GuidingLight extends ClericSpell {
@Override
public int icon() {
return HeroIcon.ELEMENTAL_BLAST; //TODO unique icon
return HeroIcon.GUIDING_LIGHT;
}
@Override
@@ -81,7 +81,7 @@ public class GuidingLight extends ClericSpell {
}
}
tome.spendCharge( 1f );
tome.spendCharge( chargeUse(hero) );
hero.spend( 1f );
hero.next();
}

View File

@@ -37,12 +37,7 @@ public class HolyWard extends ClericSpell {
@Override
public int icon() {
return HeroIcon.ENDURE; //TODO unique icon
}
@Override
public float chargeUse(Hero hero) {
return 1;
return HeroIcon.HOLY_WARD;
}
@Override
@@ -52,7 +47,7 @@ public class HolyWard extends ClericSpell {
Item.updateQuickslot();
Sample.INSTANCE.play(Assets.Sounds.READ);
tome.spendCharge( 1f );
tome.spendCharge( chargeUse(hero) );
hero.sprite.operate(hero.pos);
hero.spend( 1f );
hero.next();
@@ -60,9 +55,20 @@ public class HolyWard extends ClericSpell {
public static class HolyArmBuff extends FlavourBuff {
public static final float DURATION = 50f;
{
type = buffType.POSITIVE;
}
@Override
public int icon() {
return BuffIndicator.ARMOR;
return BuffIndicator.HOLY_ARMOR;
}
@Override
public float iconFadePercent() {
return Math.max(0, (DURATION - visualcooldown()) / DURATION);
}
@Override

View File

@@ -37,7 +37,7 @@ public class HolyWeapon extends ClericSpell {
@Override
public int icon() {
return HeroIcon.ELEMENTAL_STRIKE; //TODO unique icon
return HeroIcon.HOLY_WEAPON;
}
@Override
@@ -52,7 +52,7 @@ public class HolyWeapon extends ClericSpell {
Item.updateQuickslot();
Sample.INSTANCE.play(Assets.Sounds.READ);
tome.spendCharge( 2f );
tome.spendCharge( chargeUse(hero) );
hero.sprite.operate(hero.pos);
hero.spend( 1f );
hero.next();
@@ -60,9 +60,20 @@ public class HolyWeapon extends ClericSpell {
public static class HolyWepBuff extends FlavourBuff {
public static final float DURATION = 50f;
{
type = buffType.POSITIVE;
}
@Override
public int icon() {
return BuffIndicator.WEAPON;
return BuffIndicator.HOLY_WEAPON;
}
@Override
public float iconFadePercent() {
return Math.max(0, (DURATION - visualcooldown()) / DURATION);
}
@Override

View File

@@ -61,8 +61,7 @@ public class HolyTome extends Artifact {
ArrayList<String> actions = super.actions( hero );
if (isEquipped( hero )
&& !cursed
&& hero.buff(MagicImmune.class) == null
&& charge > 0) {
&& hero.buff(MagicImmune.class) == null) {
actions.add(AC_CAST);
}
return actions;
@@ -78,7 +77,6 @@ public class HolyTome extends Artifact {
if (action.equals(AC_CAST)) {
if (!isEquipped(hero)) GLog.i(Messages.get(Artifact.class, "need_to_equip"));
else if (charge == 0) GLog.i(Messages.get(this, "no_charge"));
else {
GameScene.show(new WndClericSpells(this, hero, false));

View File

@@ -122,6 +122,8 @@ public class BuffIndicator extends Component {
public static final int DAZE = 70;
public static final int DISGUISE = 71;
public static final int WAND = 72;
public static final int HOLY_WEAPON = 73;
public static final int HOLY_ARMOR = 74;
public static final int SIZE_SMALL = 7;
public static final int SIZE_LARGE = 16;

View File

@@ -67,16 +67,19 @@ public class HeroIcon extends Image {
public static final int FEINT = 30;
public static final int RATMOGRIFY = 31;
//action indicator visuals
public static final int BERSERK = 32;
public static final int COMBO = 33;
public static final int PREPARATION = 34;
public static final int MOMENTUM = 35;
public static final int SNIPERS_MARK = 36;
public static final int WEAPON_SWAP = 37;
public static final int MONK_ABILITIES = 38;
//cleric spells
public static final int GUIDING_LIGHT = 40;
public static final int HOLY_WEAPON = 41;
public static final int HOLY_WARD = 42;
//action indicator visuals
public static final int BERSERK = 80;
public static final int COMBO = 81;
public static final int PREPARATION = 82;
public static final int MOMENTUM = 83;
public static final int SNIPERS_MARK = 84;
public static final int WEAPON_SWAP = 85;
public static final int MONK_ABILITIES = 86;
public HeroIcon(HeroSubClass subCls){

View File

@@ -21,14 +21,15 @@
package com.shatteredpixel.shatteredpixeldungeon.windows;
import com.shatteredpixel.shatteredpixeldungeon.Chrome;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
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.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
@@ -38,6 +39,7 @@ import com.shatteredpixel.shatteredpixeldungeon.ui.Icons;
import com.shatteredpixel.shatteredpixeldungeon.ui.QuickSlotButton;
import com.shatteredpixel.shatteredpixeldungeon.ui.RenderedTextBlock;
import com.shatteredpixel.shatteredpixeldungeon.ui.Window;
import com.watabou.noosa.NinePatch;
import java.util.ArrayList;
@@ -45,9 +47,11 @@ public class WndClericSpells extends Window {
protected static final int WIDTH = 120;
public static int BTN_SIZE = 20;
public WndClericSpells(HolyTome tome, Hero cleric, boolean info){
IconTitle title = new IconTitle(new ItemSprite(tome), info ? "Spell Info" : "Cast A Spell");
IconTitle title = new IconTitle(new ItemSprite(tome), Messages.titleCase(Messages.get( this, info ? "info_title" : "cast_title")));
title.setRect(0, 0, WIDTH, 0);
add(title);
@@ -63,7 +67,7 @@ public class WndClericSpells extends Window {
add(btnInfo);
//TODO we might want to intercept quickslot hotkeys and auto-cast the last spell if relevant
RenderedTextBlock msg = PixelScene.renderTextBlock( info ? "Select a spell to learn about it, or press the info button to switch to cast mode." : "Select a spell to cast it, or press the info button to switch to info mode.", 6);
RenderedTextBlock msg = PixelScene.renderTextBlock( Messages.get( this, info ? "info_desc" : "cast_desc"), 6);
msg.maxWidth(WIDTH);
msg.setPos(0, title.bottom()+4);
add(msg);
@@ -77,33 +81,15 @@ public class WndClericSpells extends Window {
ArrayList<IconButton> spellBtns = new ArrayList<>();
for (ClericSpell spell : spells){
IconButton spellBtn = new IconButton(new HeroIcon(spell)){
@Override
protected void onClick() {
if (info){
ShatteredPixelDungeon.scene().addToFront(new WndTitledMessage(new HeroIcon(spell), spell.name(), spell.desc()));
} else {
hide();
spell.use(tome, cleric);
//TODO, probably need targeting logic here
if (spell.useTargeting() && Dungeon.quickslot.contains(tome)){
QuickSlotButton.useTargeting(Dungeon.quickslot.getSlot(tome));
}
}
}
};
if (!info && !tome.canCast(cleric, spell)){
spellBtn.enable(false);
}
IconButton spellBtn = new SpellButton(spell, tome, info);
add(spellBtn);
spellBtns.add(spellBtn);
}
//TODO rows?
int left = 0;
//TODO rows? Maybe based on spell tiers?
int left = 2 + (WIDTH-spellBtns.size()*(BTN_SIZE+4))/2;
for (IconButton btn : spellBtns){
btn.setRect(left, msg.bottom()+4, 20, 20);
btn.setRect(left, msg.bottom()+4, BTN_SIZE, BTN_SIZE);
left += btn.width()+4;
}
@@ -113,4 +99,54 @@ public class WndClericSpells extends Window {
//TODO we probably want to offset this window for mobile so it appears closer to quickslots
public class SpellButton extends IconButton {
ClericSpell spell;
HolyTome tome;
boolean info;
NinePatch bg;
public SpellButton(ClericSpell spell, HolyTome tome, boolean info){
super(new HeroIcon(spell));
this.spell = spell;
this.tome = tome;
this.info = info;
if (!info && !tome.canCast(Dungeon.hero, spell)){
enable(false);
}
bg = Chrome.get(Chrome.Type.TOAST);
addToBack(bg);
}
@Override
protected void layout() {
super.layout();
if (bg != null) {
bg.size(width, height);
bg.x = x;
bg.y = y;
}
}
@Override
protected void onClick() {
if (info){
GameScene.show(new WndTitledMessage(new HeroIcon(spell), Messages.titleCase(spell.name()), spell.desc()));
} else {
hide();
spell.use(tome, Dungeon.hero);
//TODO, probably need targeting logic here
if (spell.useTargeting() && Dungeon.quickslot.contains(tome)){
QuickSlotButton.useTargeting(Dungeon.quickslot.getSlot(tome));
}
}
}
}
}