From 6be4556112f4a0e9d1c1e0e11378207aa18e218d Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Wed, 16 Oct 2024 17:30:04 -0400 Subject: [PATCH] v3.0.0: Implemented an initial basic spell for the cleric --- .../assets/messages/actors/actors.properties | 5 ++ .../actors/hero/spells/ClericSpell.java | 88 +++++++++++++++++++ .../actors/hero/spells/GuidingLight.java | 78 ++++++++++++++++ .../items/armor/glyphs/AntiMagic.java | 3 + .../items/artifacts/HolyTome.java | 23 +++-- 5 files changed, 188 insertions(+), 9 deletions(-) create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/ClericSpell.java create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 48650b4c1..21f063774 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -532,6 +532,11 @@ actors.hero.abilities.ratmogrify$transmograt.name=ratmogrified %s actors.hero.abilities.ratmogrify$transmograt.desc=This enemy has been transformed into a rat. A big improvement, if you ask me! - Rat King actors.hero.abilities.ratmogrify$transmograt.rankings_desc=Slain by: ratmogrified enemy +##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 + ##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/ClericSpell.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/ClericSpell.java new file mode 100644 index 000000000..096ab6835 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/ClericSpell.java @@ -0,0 +1,88 @@ +/* + * 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.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.CellSelector; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; + +public abstract class ClericSpell { + + public void use(HolyTome tome, Hero hero ){ + if (targetingPrompt() == null){ + activate(tome, hero, hero.pos); + } else { + GameScene.selectCell(new CellSelector.Listener() { + @Override + public void onSelect(Integer cell) { + activate(tome, hero, cell); + } + + @Override + public String prompt() { + return targetingPrompt(); + } + }); + } + } + + //leave null for no targeting + public String targetingPrompt(){ + return null; + } + + public boolean useTargeting(){ + return targetingPrompt() != null; + } + + public int targetedPos(Char user, int dst ){ + return new Ballistica( user.pos, dst, Ballistica.PROJECTILE ).collisionPos; + } + + public float chargeUse( Hero hero ){ + return 1; + } + + protected abstract void activate( HolyTome tome, Hero hero, Integer target ); + + public String name(){ + return Messages.get(this, "name"); + } + + public String shortDesc(){ + return Messages.get(this, "short_desc"); + } + + public String desc(){ + return Messages.get(this, "desc"); + } + + public int icon(){ + return HeroIcon.NONE; + } + +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java new file mode 100644 index 000000000..501dc3260 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/spells/GuidingLight.java @@ -0,0 +1,78 @@ +/* + * 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.Actor; +import com.shatteredpixel.shatteredpixeldungeon.actors.Char; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile; +import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand; +import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Callback; +import com.watabou.utils.Random; + +public class GuidingLight extends ClericSpell { + + @Override + public String targetingPrompt() { + return Messages.get(this, "prompt"); + } + + @Override + protected void activate(HolyTome tome, Hero hero, Integer target) { + if (target == null){ + return; + } + + Ballistica aim = new Ballistica(hero.pos, target, Ballistica.MAGIC_BOLT); + + if (Actor.findChar( aim.collisionPos ) == hero){ + GLog.i( Messages.get(Wand.class, "self_target") ); + return; + } + + 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() { + @Override + public void call() { + + Char ch = Actor.findChar( aim.collisionPos ); + if (ch != null) { + ch.damage(Random.NormalIntRange(2, 6), GuidingLight.this); + Sample.INSTANCE.play(Assets.Sounds.HIT_MAGIC, 1, Random.Float(0.87f, 1.15f)); + } + //TODO needs an on-hit effect as well + + tome.spendCharge( 1f ); + hero.spend( 1f ); + hero.next(); + } + }); + } +} 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 64a5d7d2d..2c5e4cc18 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 @@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.ElementalStrike; 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.mobs.CrystalWisp; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM100; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Eye; @@ -88,6 +89,8 @@ public class AntiMagic extends Armor.Glyph { RESISTS.add( ScrollOfTeleportation.class ); RESISTS.add( HolyDart.class ); + RESISTS.add( GuidingLight.class ); + RESISTS.add( ElementalBlast.class ); RESISTS.add( CursedWand.class ); RESISTS.add( WandOfBlastWave.class ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/HolyTome.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/HolyTome.java index 68f045c9c..a0e4ce4bd 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/HolyTome.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/artifacts/HolyTome.java @@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon.items.artifacts; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.MagicImmune; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.GuidingLight; import com.shatteredpixel.shatteredpixeldungeon.items.Item; import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEnergy; import com.shatteredpixel.shatteredpixeldungeon.journal.Catalog; @@ -73,26 +74,28 @@ public class HolyTome extends Artifact { if (hero.buff(MagicImmune.class) != null) return; if (action.equals(AC_CAST)) { + usesTargeting = false; if (!isEquipped(hero)) GLog.i(Messages.get(Artifact.class, "need_to_equip")); else if (charge == 0) GLog.i(Messages.get(this, "no_charge")); else { - //TODO cast an actual spell! - charge--; - gainExp( 1 ); - updateQuickslot(); - - hero.spend( 1f ); - hero.busy(); - hero.sprite.operate(hero.pos); + //TODO need to flow into spell selection and not just auto-cast guiding light + usesTargeting = true; + new GuidingLight().use(this, hero); } } } - private void gainExp( float chargesSpent ){ + public void spendCharge( float chargesSpent ){ + partialCharge -= chargesSpent; + while (partialCharge < 0){ + charge--; + partialCharge++; + } + //target hero level is 1 + 2*tome level int lvlDiffFromTarget = Dungeon.hero.lvl - (1+level()*2); //plus an extra one for each level after 6 @@ -113,6 +116,8 @@ public class HolyTome extends Artifact { GLog.p(Messages.get(this, "levelup")); } + + updateQuickslot(); } @Override