v3.0.0: implemented the beaming ray talent/spell
This commit is contained in:
@@ -610,6 +610,14 @@ actors.hero.spells.auraofprotection.desc=The Paladin begins radiating protective
|
||||
actors.hero.spells.auraofprotection$aurabuff.name=aura of protection
|
||||
actors.hero.spells.auraofprotection$aurabuff.desc=The Paladin is radiating protective energy around themselves.\n\nAny nearby ally (including the Paladin themselves) takes reduced damage and gains the effect of the Paladin's armor glyph with boosted power.\n\nTurns Remaining: %s.
|
||||
|
||||
actors.hero.spells.beamingray.name=beaming ray
|
||||
actors.hero.spells.beamingray.no_space=There's no space for your ally to appear there.
|
||||
actors.hero.spells.beamingray.out_of_range=That location is out of range.
|
||||
actors.hero.spells.beamingray.short_desc=Teleports your ally and grants bonus damage.
|
||||
actors.hero.spells.beamingray.desc=The Cleric channels the power on their ally into a ray of light that beams them to a location. If the ray collides with an enemy it will place the ally nearby and direct them towards the enemy.\n\nThe ray has a maximum range of %1$d tiles, and will increase Power of Many's bonus damage to +%2$d%% for 10 turns against the closest enemy within 4 tiles.
|
||||
actors.hero.spells.beamingray$beamingrayboost.name=beaming ray
|
||||
actors.hero.spells.beamingray$beamingrayboost.desc=This ally was recently teleported by Beaming Ray, giving them bonus damage against the nearest enemy after the teleport. Power of Many also won't expire when this buff is active.\n\nTurns Remaining: %s.
|
||||
|
||||
actors.hero.spells.blessspell.name=bless
|
||||
actors.hero.spells.blessspell.short_desc=Blesses & shields Cleric, blesses & heals others.
|
||||
actors.hero.spells.blessspell.desc=The Cleric places a holy blessing on themselves or another character they can see.\n\nWhen cast on themselves the effect is weaker, granting %1$d turns of bless and %2$d barrier.\n\nWhen cast on other characters the spell is more powerful, granting %3$d turns of bless and %4$d healing. Excess healing is converted into barrier.
|
||||
@@ -1237,7 +1245,7 @@ actors.hero.talent.spirit_form.title=spirit form
|
||||
actors.hero.talent.spirit_form.desc=The Cleric can cast _Spirit Form_, which imbues Trinity with the power of a ring or artifact that the Cleric has identified this run (except the holy tome), at the cost of 4 charges.\n\n_+1:_ When Trinity is used, the Cleric will gain a ring's effect at _+1_ for 20 turns, or will trigger an artifact's effect at _+4._\n\n_+2:_ When Trinity is used, the Cleric will gain a ring's effect at _+2_ for 20 turns, or will trigger an artifact's effect at _+6._\n\n_+3:_ When Trinity is used, the Cleric will gain a ring's effect at _+3_ for 20 turns, or will trigger an artifact's effect at _+8._\n\n_+4:_ When Trinity is used, the Cleric will gain a ring's effect at _+4_ for 20 turns, or will trigger an artifact's effect at _+10._\n\nTrinity can only be imbued with one spirit effect at a time. Artifacts have varied effects and armor charge costs when triggered by Trinity.
|
||||
|
||||
actors.hero.talent.beaming_ray.title=beaming ray
|
||||
actors.hero.talent.beaming_ray.desc=The Cleric can cast _Beaming Ray_ from an empowered ally at the cost of 1 charge. This ray can go through walls and teleports the ally to a targeted location. If an enemy is at that location, the ally appears next to the enemy and will target them.\n\n_+1:_ Beaming Ray has a max range of 4 tiles, and grants your ally an additional _+10% damage_ against the closest enemy for 10 turns.\n\n_+2:_ Beaming Ray has a max range of 8 tiles, and grants your ally an additional _+15% damage_ against the closest enemy for 10 turns.\n\n_+3:_ Beaming Ray has a max range of 12 tiles, and grants your ally an additional _+20% damage_ against the closest enemy for 10 turns.\n\n_+4:_ Beaming Ray has a max range of 16 tiles, and grants your ally an additional _+25% damage_ against the closest enemy for 10 turns.
|
||||
actors.hero.talent.beaming_ray.desc=The Cleric can cast _Beaming Ray_ from an empowered ally at the cost of 1 charge. This ray can go through walls and teleports the ally to a targeted location. If an enemy is at that location, the ally appears next to the enemy and will target them.\n\n_+1:_ Beaming Ray has a max range of 4 tiles, and increases Power of Many's bonus to _+35% damage_ against the closest enemy for 10 turns.\n\n_+2:_ Beaming Ray has a max range of 8 tiles, and increases Power of Many's bonus to _+40% damage_ against the closest enemy for 10 turns.\n\n_+3:_ Beaming Ray has a max range of 12 tiles, and increases Power of Many's bonus to _+45% damage_ against the closest enemy for 10 turns.\n\n_+4:_ Beaming Ray has a max range of 16 tiles, and increases Power of Many's bonus to _+50% damage_ against the closest enemy for 10 turns.
|
||||
actors.hero.talent.life_link.title=life link
|
||||
actors.hero.talent.life_link.desc=The Cleric can cast _Life Link_ between themselves and an empowered ally at the cost of 2 charges. This spell causes damage to be shared between the Cleric and their ally, and causes beneficial spells to apply to both if either is being targeted.\n\n_+1:_ Life Link lasts for _6 turns_ and grants the ally an additional _-10% damage taken._\n\n_+2:_ Life Link lasts for _8 turns_ and grants the ally an additional _-15% damage taken._\n\n_+3:_ Life Link lasts for _10 turns_ and grants the ally an additional _-20% damage taken._\n\n_+4:_ Life Link lasts for _12 turns_ and grants the ally an additional _-25% damage taken._\n\nSpells that can be shared are: shield of light, divine sense, bless, hallowed ground, mnemonic prayer, lay on hands, aura of protection.
|
||||
actors.hero.talent.stasis.title=Stasis
|
||||
|
||||
@@ -82,6 +82,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Ch
|
||||
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.AuraOfProtection;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.BeamingRay;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.GuidingLight;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.ShieldOfLight;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Brute;
|
||||
@@ -427,7 +428,12 @@ public abstract class Char extends Actor {
|
||||
}
|
||||
|
||||
if (buff( PowerOfMany.PowerBuff.class) != null){
|
||||
dmg *= 1.25f;
|
||||
if (buff( BeamingRay.BeamingRayBoost.class) != null
|
||||
&& buff( BeamingRay.BeamingRayBoost.class).object == enemy.id()){
|
||||
dmg *= 1.3f + 0.05f*Dungeon.hero.pointsInTalent(Talent.BEAMING_RAY);
|
||||
} else {
|
||||
dmg *= 1.25f;
|
||||
}
|
||||
}
|
||||
|
||||
for (ChampionEnemy buff : buffs(ChampionEnemy.class)){
|
||||
|
||||
@@ -35,6 +35,7 @@ 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.abilities.ArmorAbility;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.BeamingRay;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
@@ -90,6 +91,10 @@ public class PowerOfMany extends ArmorAbility {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean useTargeting(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate(ClassArmor armor, Hero hero, Integer target) {
|
||||
|
||||
@@ -167,7 +172,7 @@ public class PowerOfMany extends ArmorAbility {
|
||||
return new Talent[]{Talent.BEAMING_RAY, Talent.LIFE_LINK, Talent.STASIS, Talent.HEROIC_ENERGY};
|
||||
}
|
||||
|
||||
private static Char getPoweredAlly(){
|
||||
public static Char getPoweredAlly(){
|
||||
for (Char ch : Actor.chars()){
|
||||
if (ch.buff(PowerBuff.class) != null){
|
||||
return ch;
|
||||
@@ -201,6 +206,15 @@ public class PowerOfMany extends ArmorAbility {
|
||||
else target.sprite.remove(CharSprite.State.GLOWING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean act() {
|
||||
if (target.buff(BeamingRay.BeamingRayBoost.class) != null){
|
||||
spend(TICK);
|
||||
return true;
|
||||
}
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void detach() {
|
||||
super.detach();
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
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.actors.hero.abilities.cleric.PowerOfMany;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.PathFinder;
|
||||
|
||||
public class BeamingRay extends TargetedClericSpell {
|
||||
|
||||
public static BeamingRay INSTANCE = new BeamingRay();
|
||||
|
||||
@Override
|
||||
public int icon() {
|
||||
return HeroIcon.BEAMING_RAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String desc() {
|
||||
return Messages.get(this, "desc", 4*Dungeon.hero.pointsInTalent(Talent.BEAMING_RAY), 30 + 5*Dungeon.hero.pointsInTalent(Talent.BEAMING_RAY)) + "\n\n" + Messages.get(this, "charge_cost", (int)chargeUse(Dungeon.hero));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int targetingFlags() {
|
||||
return Ballistica.STOP_TARGET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canCast(Hero hero) {
|
||||
return super.canCast(hero)
|
||||
&& hero.hasTalent(Talent.BEAMING_RAY)
|
||||
&& PowerOfMany.getPoweredAlly() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTargetSelected(HolyTome tome, Hero hero, Integer target) {
|
||||
if (target == null){
|
||||
return;
|
||||
}
|
||||
|
||||
Char ally = PowerOfMany.getPoweredAlly();
|
||||
|
||||
int telePos = target;
|
||||
|
||||
if (Dungeon.level.solid[telePos] || !Dungeon.level.heroFOV[telePos] || Actor.findChar(telePos) != null){
|
||||
telePos = -1;
|
||||
for (int i : PathFinder.NEIGHBOURS8){
|
||||
if (Actor.findChar(target+i) == null && !Dungeon.level.solid[target+i] && Dungeon.level.heroFOV[target+i]){
|
||||
if (telePos == -1 || Dungeon.level.trueDistance(telePos, ally.pos) > Dungeon.level.trueDistance(target+i, ally.pos)){
|
||||
telePos = target+i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (telePos == -1){
|
||||
GLog.w(Messages.get(this, "no_space"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Dungeon.level.distance(ally.pos, telePos) > 4*hero.pointsInTalent(Talent.BEAMING_RAY)){
|
||||
GLog.w(Messages.get(this, "out_of_range"));
|
||||
return;
|
||||
}
|
||||
|
||||
Char chTarget = null;
|
||||
if (Actor.findChar(target) != null && Actor.findChar(target).alignment == Char.Alignment.ENEMY){
|
||||
chTarget = Actor.findChar(target);
|
||||
}
|
||||
|
||||
hero.sprite.zap(telePos);
|
||||
hero.sprite.parent.add(
|
||||
new Beam.SunRay(ally.sprite.center(), DungeonTilemap.raisedTileCenterToWorld(telePos)));
|
||||
ScrollOfTeleportation.appear(ally, telePos);
|
||||
|
||||
if (chTarget == null){
|
||||
for (Char ch : Actor.chars()){
|
||||
if (ch.alignment == Char.Alignment.ENEMY && Dungeon.level.distance(ch.pos, telePos) <= 4){
|
||||
if (chTarget == null || Dungeon.level.trueDistance(chTarget.pos, ally.pos) < Dungeon.level.trueDistance(ch.pos, ally.pos)) {
|
||||
chTarget = ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (chTarget != null) {
|
||||
if (ally instanceof DirectableAlly) {
|
||||
((DirectableAlly) ally).targetChar(chTarget);
|
||||
} else if (ally instanceof Mob) {
|
||||
((Mob) ally).aggro(chTarget);
|
||||
}
|
||||
FlavourBuff.prolong(ally, BeamingRayBoost.class, BeamingRayBoost.DURATION).object = chTarget.id();
|
||||
} else {
|
||||
//just the buff with no target
|
||||
FlavourBuff.prolong(ally, BeamingRayBoost.class, BeamingRayBoost.DURATION);
|
||||
}
|
||||
|
||||
hero.spendAndNext(Actor.TICK);
|
||||
Dungeon.observe();
|
||||
GameScene.updateFog();
|
||||
|
||||
onSpellCast(tome, hero);
|
||||
}
|
||||
|
||||
public static class BeamingRayBoost extends FlavourBuff {
|
||||
|
||||
{
|
||||
type = buffType.POSITIVE;
|
||||
}
|
||||
|
||||
public int object = 0;
|
||||
|
||||
public static final float DURATION = 10f;
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int icon() {
|
||||
return BuffIndicator.HOLY_WEAPON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float iconFadePercent() {
|
||||
return Math.max(0, (DURATION - visualcooldown()) / DURATION);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -184,6 +184,10 @@ public abstract class ClericSpell {
|
||||
spells.add(SpiritForm.INSTANCE);
|
||||
}
|
||||
|
||||
if (cleric.hasTalent(Talent.BEAMING_RAY)){
|
||||
spells.add(BeamingRay.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return spells;
|
||||
@@ -212,6 +216,10 @@ public abstract class ClericSpell {
|
||||
spells.add(DivineIntervention.INSTANCE);
|
||||
spells.add(Judgement.INSTANCE);
|
||||
spells.add(Flash.INSTANCE);
|
||||
spells.add(BodyForm.INSTANCE);
|
||||
spells.add(MindForm.INSTANCE);
|
||||
spells.add(SpiritForm.INSTANCE);
|
||||
spells.add(BeamingRay.INSTANCE);
|
||||
return spells;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user