v3.0.0: implemented the Hallowed Ground spell/talent
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
@@ -554,8 +554,15 @@ actors.hero.spells.cleanse.desc=The Cleric instantly clears all harmful effects
|
||||
|
||||
actors.hero.spells.clericspell.prompt=Choose a target
|
||||
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.charge_cost=Charge cost: %d
|
||||
|
||||
actors.hero.spells.hallowedground.name=hallowed ground
|
||||
actors.hero.spells.hallowedground.prompt=choose a location
|
||||
actors.hero.spells.hallowedground.short_desc=Heals allies, slows enemies, and spreads grass in an AOE.
|
||||
actors.hero.spells.hallowedground.desc=The Priest focuses their divine magic into the ground nearby, creating a %1$dx%1$d area of hallowed terrain for 20 turns.\n\nWhen it is cast, this spell heals all allies for 10 HP (healthy allies and the Priest get shielding), briefly roots enemies, and spreads short grass.\n\nThe hallowed terrain heals allies for 1 HP per turn (healthy allies and the Priest get shielding), cripples enemies, and randomly causes tall grass to grow.\n\nHallowed terrain is destroyed by fire, and will produce furrowed grass if passive regen effects are disabled or the Priest has not gained exp in a while.
|
||||
actors.hero.spells.hallowedground$hallowedterrain.desc=The ground has been hallowed here. Hallowed ground slowly enemies, heals allies, and causes grass to spread.
|
||||
|
||||
actors.hero.spells.holyintuition.name=holy intuition
|
||||
actors.hero.spells.holyintuition.prompt=choose an item
|
||||
actors.hero.spells.holyintuition.cursed=You sense malevolent magic lurking within this item.
|
||||
@@ -1082,8 +1089,8 @@ actors.hero.talent.light_reading.desc=_+1:_ The Cleric can use their holy tome w
|
||||
|
||||
actors.hero.talent.holy_lance.title=Holy Lance
|
||||
actors.hero.talent.holy_lance.desc=_+1:_ The Priest can cast _Holy Lance,_ a devastating spell that deals _30-55 damage_ at the cost of 4 charges.\n\n_+2:_ The Priest can cast _Holy Lance,_ a devastating spell that deals _45-83 damage_ at the cost of 4 charges.\n\n_+3:_ The Priest can cast _Holy Lance,_ a devastating spell that deals _60-110 damage_ at the cost of 4 charges.\n\nHoly Lance always deals maximum damage to demonic and undead foes. Holy Lance has a 50 turn cooldown before it can be cast again.
|
||||
actors.hero.talent.priestt3b.title=Unknown
|
||||
actors.hero.talent.priestt3b.desc=This talent hasn't been implemented yet, it currently does nothing.
|
||||
actors.hero.talent.hallowed_ground.title=Hallowed Ground
|
||||
actors.hero.talent.hallowed_ground.desc=_+1:_ The Priest can cast _Hallowed Ground,_ a spell that hallows terrain in a _3x3 area_ for 20 turns, at the cost of 2 charges.\n\n_+2:_ The Priest can cast _Hallowed Ground,_ a spell that hallows terrain in a _5x5 area_ for 20 turns, at the cost of 2 charges.\n\n_+3:_ The Priest can cast _Hallowed Ground,_ a spell that hallows terrain in a _7x7 area_ for 20 turns, at the cost of 2 charges.\n\nWhen it is cast, Hallowed Ground heals allies for 10 HP, briefly roots enemies, and spreads short grass. Afterward, it slowly heals allies, cripples enemies, and causes tall grass to randomly grow. Hallowed ground grants shielding to the Priest instead of healing and is destroyed by fire.
|
||||
actors.hero.talent.priestt3c.title=Unknown
|
||||
actors.hero.talent.priestt3c.desc=This talent hasn't been implemented yet, it currently does nothing.
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Ch
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.ElementalStrike;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.NaturesPower;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.Endure;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.HallowedGround;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk;
|
||||
@@ -1907,6 +1908,12 @@ public class Hero extends Char {
|
||||
buff(ElementalStrike.ElementalStrikeFurrowCounter.class).detach();
|
||||
}
|
||||
}
|
||||
if (buff(HallowedGround.HallowedFurrowTracker.class) != null){
|
||||
buff(ElementalStrike.ElementalStrikeFurrowCounter.class).countDown(percent*5f);
|
||||
if (buff(ElementalStrike.ElementalStrikeFurrowCounter.class).count() <= 0){
|
||||
buff(ElementalStrike.ElementalStrikeFurrowCounter.class).detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean levelUp = false;
|
||||
|
||||
@@ -181,7 +181,7 @@ public enum Talent {
|
||||
//Cleric T3
|
||||
CLEANSE(169, 3), LIGHT_READING(170, 3),
|
||||
//Priest T3
|
||||
HOLY_LANCE(171, 3), PRIESTT3B(172, 3), PRIESTT3C(173, 3),
|
||||
HOLY_LANCE(171, 3), HALLOWED_GROUND(172, 3), PRIESTT3C(173, 3),
|
||||
//Paladin T3
|
||||
PALADINT3A(174, 3), PALADINT3B(175, 3), PALADINT3C(176, 3),
|
||||
//Cleric A1 T4
|
||||
@@ -1019,7 +1019,7 @@ public enum Talent {
|
||||
Collections.addAll(tierTalents, UNENCUMBERED_SPIRIT, MONASTIC_VIGOR, COMBINED_ENERGY);
|
||||
break;
|
||||
case PRIEST:
|
||||
Collections.addAll(tierTalents, HOLY_LANCE, PRIESTT3B, PRIESTT3C);
|
||||
Collections.addAll(tierTalents, HOLY_LANCE, HALLOWED_GROUND, PRIESTT3C);
|
||||
break;
|
||||
case PALADIN:
|
||||
Collections.addAll(tierTalents, PALADINT3A, PALADINT3B, PALADINT3C);
|
||||
|
||||
@@ -76,12 +76,15 @@ public class BlessSpell extends TargetedClericSpell {
|
||||
int totalHeal = 5 + 10*hero.pointsInTalent(Talent.BLESS);
|
||||
if (ch.HT - ch.HP < totalHeal){
|
||||
int barrier = totalHeal - (ch.HT - ch.HP);
|
||||
barrier = Math.max(barrier, 0);
|
||||
if (ch.HP != ch.HT) {
|
||||
ch.HP = ch.HT;
|
||||
ch.sprite.showStatusWithIcon(CharSprite.POSITIVE, Integer.toString(totalHeal - barrier), FloatingText.HEALING);
|
||||
}
|
||||
Buff.affect(ch, Barrier.class).setShield(barrier);
|
||||
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(barrier), FloatingText.SHIELDING );
|
||||
if (barrier > 0) {
|
||||
Buff.affect(ch, Barrier.class).setShield(barrier);
|
||||
ch.sprite.showStatusWithIcon(CharSprite.POSITIVE, Integer.toString(barrier), FloatingText.SHIELDING);
|
||||
}
|
||||
} else {
|
||||
ch.HP = ch.HP + totalHeal;
|
||||
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(totalHeal), FloatingText.HEALING );
|
||||
|
||||
@@ -124,6 +124,10 @@ public abstract class ClericSpell {
|
||||
spells.add(HolyLance.INSTANCE);
|
||||
}
|
||||
|
||||
if (cleric.hasTalent(Talent.HALLOWED_GROUND)){
|
||||
spells.add(HallowedGround.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return spells;
|
||||
@@ -143,6 +147,7 @@ public abstract class ClericSpell {
|
||||
spells.add(Cleanse.INSTANCE);
|
||||
spells.add(Radiance.INSTANCE);
|
||||
spells.add(HolyLance.INSTANCE);
|
||||
spells.add(HallowedGround.INSTANCE);
|
||||
return spells;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.blobs.Blob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Fire;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.CounterBuff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Cripple;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Regeneration;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.BlobEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.FloatingText;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShaftParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.HolyTome;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.watabou.utils.BArray;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class HallowedGround extends TargetedClericSpell {
|
||||
|
||||
public static final HallowedGround INSTANCE = new HallowedGround();
|
||||
|
||||
@Override
|
||||
public int icon() {
|
||||
return HeroIcon.HALLOWED_GROUND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float chargeUse(Hero hero) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTargetSelected(HolyTome tome, Hero hero, Integer target) {
|
||||
|
||||
if (target == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if (Dungeon.level.solid[target] || !Dungeon.level.heroFOV[target]){
|
||||
GLog.w(Messages.get(this, "invalid_target"));
|
||||
return;
|
||||
}
|
||||
|
||||
PathFinder.buildDistanceMap(target, BArray.not(Dungeon.level.solid, null), hero.pointsInTalent(Talent.HALLOWED_GROUND));
|
||||
for (int i = 0; i < Dungeon.level.length(); i++){
|
||||
if (PathFinder.distance[i] != Integer.MAX_VALUE){
|
||||
int c = Dungeon.level.map[i];
|
||||
if (c == Terrain.EMPTY || c == Terrain.EMBERS || c == Terrain.EMPTY_DECO) {
|
||||
Level.set( i, Terrain.GRASS);
|
||||
GameScene.updateMap( i );
|
||||
CellEmitter.get(i).burst(LeafParticle.LEVEL_SPECIFIC, 2);
|
||||
}
|
||||
GameScene.add(Blob.seed(i, 20, HallowedTerrain.class));
|
||||
CellEmitter.get(i).burst(ShaftParticle.FACTORY, 2);
|
||||
|
||||
Char ch = Actor.findChar(i);
|
||||
if (ch != null){
|
||||
if (ch.alignment == Char.Alignment.ALLY){
|
||||
|
||||
if (ch == Dungeon.hero || ch.HP == ch.HT){
|
||||
Buff.affect(ch, Barrier.class).incShield(10);
|
||||
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "10", FloatingText.SHIELDING );
|
||||
} else {
|
||||
int barrier = 10 - (ch.HT - ch.HP);
|
||||
barrier = Math.max(barrier, 0);
|
||||
ch.HP += 10 - barrier;
|
||||
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(10-barrier), FloatingText.HEALING );
|
||||
if (barrier > 0){
|
||||
Buff.affect(ch, Barrier.class).incShield(barrier);
|
||||
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, Integer.toString(barrier), FloatingText.SHIELDING );
|
||||
}
|
||||
}
|
||||
} else if (!ch.flying) {
|
||||
Buff.affect(ch, Roots.class, 1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//5 casts per hero level before furrowing
|
||||
Buff.affect(hero, HallowedFurrowTracker.class).countUp(1);
|
||||
|
||||
Sample.INSTANCE.play(Assets.Sounds.MELD);
|
||||
hero.sprite.zap(target);
|
||||
hero.spendAndNext( 1f );
|
||||
|
||||
onSpellCast(tome, hero);
|
||||
|
||||
}
|
||||
|
||||
public String desc(){
|
||||
int area = 1 + 2*Dungeon.hero.pointsInTalent(Talent.HALLOWED_GROUND);
|
||||
return Messages.get(this, "desc", area) + "\n\n" + Messages.get(this, "charge_cost", (int)chargeUse(Dungeon.hero));
|
||||
}
|
||||
|
||||
public static class HallowedTerrain extends Blob {
|
||||
|
||||
@Override
|
||||
protected void evolve() {
|
||||
|
||||
int cell;
|
||||
|
||||
Fire fire = (Fire)Dungeon.level.blobs.get( Fire.class );
|
||||
|
||||
// on avg, hallowed ground produces 9/17/25 tiles of grass, 100/67/50% of total tiles
|
||||
int chance = 10 + 10*Dungeon.hero.pointsInTalent(Talent.HALLOWED_GROUND);
|
||||
|
||||
for (int i = area.left-1; i <= area.right; i++) {
|
||||
for (int j = area.top-1; j <= area.bottom; j++) {
|
||||
cell = i + j*Dungeon.level.width();
|
||||
if (cur[cell] > 0) {
|
||||
|
||||
//fire destroys hallowed terrain
|
||||
if (fire != null && fire.volume > 0 && fire.cur[cell] > 0){
|
||||
off[cell] = cur[cell] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int c = Dungeon.level.map[cell];
|
||||
if (c == Terrain.GRASS) {
|
||||
if (Random.Int(chance) == 0) {
|
||||
if (!Regeneration.regenOn()
|
||||
|| (Dungeon.hero.buff(HallowedFurrowTracker.class) != null && Dungeon.hero.buff(HallowedFurrowTracker.class).count() > 5)){
|
||||
Level.set(cell, Terrain.FURROWED_GRASS);
|
||||
} else {
|
||||
Level.set(cell, Terrain.HIGH_GRASS);
|
||||
}
|
||||
GameScene.updateMap(cell);
|
||||
CellEmitter.get(cell).burst(LeafParticle.LEVEL_SPECIFIC, 5);
|
||||
}
|
||||
} else if (c == Terrain.EMPTY || c == Terrain.EMBERS || c == Terrain.EMPTY_DECO) {
|
||||
Level.set(cell, Terrain.GRASS);
|
||||
GameScene.updateMap(cell);
|
||||
CellEmitter.get(cell).burst(LeafParticle.LEVEL_SPECIFIC, 2);
|
||||
}
|
||||
|
||||
Char ch = Actor.findChar(cell);
|
||||
if (ch != null){
|
||||
if (ch.alignment == Char.Alignment.ALLY){
|
||||
if (ch == Dungeon.hero || ch.HP == ch.HT){
|
||||
Buff.affect(ch, Barrier.class).incShield(1);
|
||||
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "1", FloatingText.SHIELDING );
|
||||
} else {
|
||||
ch.HP++;
|
||||
ch.sprite.showStatusWithIcon( CharSprite.POSITIVE, "1", FloatingText.HEALING );
|
||||
}
|
||||
} else if (!ch.flying && ch.buff(Roots.class) == null){
|
||||
Buff.prolong(ch, Cripple.class, 1f);
|
||||
}
|
||||
}
|
||||
|
||||
off[cell] = cur[cell] - 1;
|
||||
volume += off[cell];
|
||||
} else {
|
||||
off[cell] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void use(BlobEmitter emitter) {
|
||||
super.use( emitter );
|
||||
emitter.pour( ShaftParticle.FACTORY, 1f );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tileDesc() {
|
||||
return Messages.get(this, "desc");
|
||||
}
|
||||
}
|
||||
|
||||
public static class HallowedFurrowTracker extends CounterBuff{{revivePersists = true;}}
|
||||
|
||||
}
|
||||
@@ -85,6 +85,7 @@ public class HeroIcon extends Image {
|
||||
public static final int CLEANSE = 49;
|
||||
public static final int RADIANCE = 50;
|
||||
public static final int HOLY_LANCE = 51;
|
||||
public static final int HALLOWED_GROUND = 52;
|
||||
|
||||
//all cleric spells have a separate icon with no background for the action indicator
|
||||
public static final int SPELL_ACTION_OFFSET = 32;
|
||||
|
||||
Reference in New Issue
Block a user