v0.9.3: implemented the endure ability

This commit is contained in:
Evan Debenham 2021-05-20 15:47:05 -04:00
parent 367a364eb3
commit 8c16cc5468
6 changed files with 154 additions and 14 deletions

View File

@ -424,7 +424,7 @@ actors.hero.heroclass.huntress_unlock=The Huntress is a master of thrown weapons
actors.hero.herosubclass.berserker=berserker actors.hero.herosubclass.berserker=berserker
actors.hero.herosubclass.berserker_short_desc=The _Berserker_ builds rage as he takes damage. Rage increases his damage, and can let him briefly cheat death. actors.hero.herosubclass.berserker_short_desc=The _Berserker_ builds rage as he takes damage. Rage increases his damage, and can let him briefly cheat death.
actors.hero.herosubclass.berserker_desc=The Berserker gains rage as he takes damage, including damage that gets blocked by his armor! Rage steadily fades away over time, but fades more slowly if he is at low HP.\n\nThe Berserker deals up to +50% damage at 100% rage. When at 0 health and 100% rage, the Berserker will briefly gain 8x his normal maximum shielding and will refuse to die as long as he has shielding left. The Berserker needs time to recover after he defies death however. actors.hero.herosubclass.berserker_desc=The Berserker gains rage as he takes physical damage, including damage that gets blocked by his armor! Rage steadily fades away over time, but fades more slowly if he is at low HP.\n\nThe Berserker deals up to +50% damage at 100% rage. When at 0 health and 100% rage, the Berserker will briefly gain 8x his normal maximum shielding and will refuse to die as long as he has shielding left. The Berserker needs time to recover after he defies death however.
actors.hero.herosubclass.gladiator=gladiator actors.hero.herosubclass.gladiator=gladiator
actors.hero.herosubclass.gladiator_short_desc=The _Gladiator_ builds combo when he makes successful attacks. He can spend combo to use unique abilities. actors.hero.herosubclass.gladiator_short_desc=The _Gladiator_ builds combo when he makes successful attacks. He can spend combo to use unique abilities.
actors.hero.herosubclass.gladiator_desc=The Gladiator builds one point of combo every time he makes a successful attack with a melee or thrown weapon. If the Gladiator does not make a successful attack within 5 turns, his combo is reset.\n\nAs combo builds it unlocks a variety of combo abilities. A new ability becomes available at 2, 4, 6, 8, and 10 combo. Some abilities help build more combo, while others let the Gladiator spend his combo on powerful attacks. actors.hero.herosubclass.gladiator_desc=The Gladiator builds one point of combo every time he makes a successful attack with a melee or thrown weapon. If the Gladiator does not make a successful attack within 5 turns, his combo is reset.\n\nAs combo builds it unlocks a variety of combo abilities. A new ability becomes available at 2, 4, 6, 8, and 10 combo. Some abilities help build more combo, while others let the Gladiator spend his combo on powerful attacks.
@ -509,12 +509,12 @@ actors.hero.talent.striking_wave.desc=_+1:_ Damage from shockwave has a _25% cha
actors.hero.talent.shock_force.title=shock force actors.hero.talent.shock_force.title=shock force
actors.hero.talent.shock_force.desc=_+1:_ Shockwave deals _20% more damage_ and has a _25% chance_ to stun instead of cripple.\n\n_+2:_ Shockwave deals _50% more damage_ and has a _50% chance_ to stun instead of cripple.\n\n_+3:_ Shockwave deals _60% more damage_ and has a _75% chance_ to stun instead of cripple.\n\n_+4:_ Shockwave deals _80% more damage_ and has a _100% chance_ to stun instead of cripple. actors.hero.talent.shock_force.desc=_+1:_ Shockwave deals _20% more damage_ and has a _25% chance_ to stun instead of cripple.\n\n_+2:_ Shockwave deals _50% more damage_ and has a _50% chance_ to stun instead of cripple.\n\n_+3:_ Shockwave deals _60% more damage_ and has a _75% chance_ to stun instead of cripple.\n\n_+4:_ Shockwave deals _80% more damage_ and has a _100% chance_ to stun instead of cripple.
actors.hero.talent.warrior_3_1.title=TODO NAME actors.hero.talent.sustained_retribution.title=sustained retribution
actors.hero.talent.warrior_3_1.desc=TODO DESC actors.hero.talent.sustained_retribution.desc=_+1:_ The Warrior deals _55% bonus damage_ over _2 hits_, instead of 100% over 1 hit.\n\n_+2:_ The Warrior deals _40% bonus damage_ over _3 hits_, instead of 100% over 1 hit.\n\n_+3:_ The Warrior deals _33% bonus damage_ over _4 hits_, instead of 100% over 1 hit.\n\n_+4:_ The Warrior deals _28% bonus damage_ over _5 hits_, instead of 100% over 1 hit.
actors.hero.talent.warrior_3_2.title=TODO NAME actors.hero.talent.shrug_it_off.title=shrug it off
actors.hero.talent.warrior_3_2.desc=TODO DESC actors.hero.talent.shrug_it_off.desc=_+1:_ The Warrior cannot take more than _76% of his max HP_ in damage while enduring.\n\n_+2:_ The Warrior cannot take more than _58% of his max HP_ in damage while enduring.\n\n_+3:_ The Warrior cannot take more than _44% of his max HP_ in damage while enduring.\n\n_+4:_ The Warrior cannot take more than _33% of his max HP_ in damage while enduring.
actors.hero.talent.warrior_3_3.title=TODO NAME actors.hero.talent.even_the_odds.title=even the odds
actors.hero.talent.warrior_3_3.desc=TODO DESC actors.hero.talent.even_the_odds.desc=_+1:_ The Warrior deals an additional _5% bonus damage_ for every enemy within 2 tiles when enduring ends.\n\n_+2:_ The Warrior deals an additional _10% bonus damage_ for every enemy within 2 tiles when enduring ends.\n\n_+3:_ The Warrior deals an additional _15% bonus damage_ for every enemy within 2 tiles when enduring ends.\n\n_+4:_ The Warrior deals an additional _20% bonus damage_ for every enemy within 2 tiles when enduring ends.
#mage #mage
actors.hero.talent.empowering_meal.title=empowering meal actors.hero.talent.empowering_meal.title=empowering meal

View File

@ -64,6 +64,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.DeathMark; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.DeathMark;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.Endure;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Elemental; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Elemental;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap; import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.AntiMagic; import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.AntiMagic;
@ -97,7 +98,6 @@ import com.watabou.utils.Bundle;
import com.watabou.utils.PathFinder; import com.watabou.utils.PathFinder;
import com.watabou.utils.Random; import com.watabou.utils.Random;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@ -326,6 +326,11 @@ public abstract class Char extends Actor {
dmg = Math.round(dmg*dmgMulti); dmg = Math.round(dmg*dmgMulti);
dmg += dmgBonus; dmg += dmgBonus;
Endure.EndureTracker endure = enemy.buff(Endure.EndureTracker.class);
if (endure != null){
dmg = endure.adjustDamageTaken(dmg);
}
int effectiveDamage = enemy.defenseProc( this, dmg ); int effectiveDamage = enemy.defenseProc( this, dmg );
effectiveDamage = Math.max( effectiveDamage - dr, 0 ); effectiveDamage = Math.max( effectiveDamage - dr, 0 );
@ -551,6 +556,11 @@ public abstract class Char extends Actor {
if (alignment != Alignment.ALLY && this.buff(DeathMark.DeathMarkTracker.class) != null){ if (alignment != Alignment.ALLY && this.buff(DeathMark.DeathMarkTracker.class) != null){
dmg *= 1.25f; dmg *= 1.25f;
} }
Endure.EndureTracker endure = buff(Endure.EndureTracker.class);
//reduce damage here if it isn't coming from a chacter (if it is we already reduced it)
if (endure != null && !(src instanceof Char)){
dmg = endure.adjustDamageTaken(dmg);
}
Class<?> srcClass = src.getClass(); Class<?> srcClass = src.getClass();
if (isImmune( srcClass )) { if (isImmune( srcClass )) {
@ -569,6 +579,10 @@ public abstract class Char extends Actor {
buff( Paralysis.class ).processDamage(dmg); buff( Paralysis.class ).processDamage(dmg);
} }
if (endure != null){
dmg = endure.enforceDamagetakenLimit(dmg);
}
int shielded = dmg; int shielded = dmg;
//FIXME: when I add proper damage properties, should add an IGNORES_SHIELDS property to use here. //FIXME: when I add proper damage properties, should add an IGNORES_SHIELDS property to use here.
if (!(src instanceof Hunger)){ if (!(src instanceof Hunger)){

View File

@ -54,6 +54,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.SnipersMark;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.NaturesPower; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.NaturesPower;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.Endure;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk;
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter; import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
@ -510,6 +511,9 @@ public class Hero extends Char {
Berserk berserk = buff(Berserk.class); Berserk berserk = buff(Berserk.class);
if (berserk != null) dmg = berserk.damageFactor(dmg); if (berserk != null) dmg = berserk.damageFactor(dmg);
Endure.EndureTracker endure = buff(Endure.EndureTracker.class);
if (endure != null) dmg = endure.damageFactor(dmg);
return buff( Fury.class ) != null ? (int)(dmg * 1.5f) : dmg; return buff( Fury.class ) != null ? (int)(dmg * 1.5f) : dmg;
} }
@ -616,6 +620,10 @@ public class Hero extends Char {
//calls to dungeon.observe will also update hero's local FOV. //calls to dungeon.observe will also update hero's local FOV.
fieldOfView = Dungeon.level.heroFOV; fieldOfView = Dungeon.level.heroFOV;
if (buff(Endure.EndureTracker.class) != null){
buff(Endure.EndureTracker.class).endEnduring();
}
if (!ready) { if (!ready) {
//do a full observe (including fog update) if not resting. //do a full observe (including fog update) if not resting.
if (!resting || buff(MindVision.class) != null || buff(Awareness.class) != null) { if (!resting || buff(MindVision.class) != null || buff(Awareness.class) != null) {

View File

@ -27,7 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.Challenges;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.QuickSlot; import com.shatteredpixel.shatteredpixeldungeon.QuickSlot;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.NaturesStrength; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.NaturesPower;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpectralBlades; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpectralBlades;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WildMagic; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.mage.WildMagic;
@ -217,7 +217,7 @@ public enum HeroClass {
case ROGUE: case ROGUE:
return new ArmorAbility[]{new SmokeBomb(), new DeathMark(), new ShadowClone()}; return new ArmorAbility[]{new SmokeBomb(), new DeathMark(), new ShadowClone()};
case HUNTRESS: case HUNTRESS:
return new ArmorAbility[]{new SpectralBlades(), new NaturesStrength(), new SpiritHawk()}; return new ArmorAbility[]{new SpectralBlades(), new NaturesPower(), new SpiritHawk()};
} }
} }

View File

@ -85,8 +85,8 @@ public enum Talent {
BODY_SLAM(17, 4), IMPACT_WAVE(18, 4), DOUBLE_JUMP(19, 4), BODY_SLAM(17, 4), IMPACT_WAVE(18, 4), DOUBLE_JUMP(19, 4),
//Shockwave T4 //Shockwave T4
EXPANDING_WAVE(20, 4), STRIKING_WAVE(21, 4), SHOCK_FORCE(22, 4), EXPANDING_WAVE(20, 4), STRIKING_WAVE(21, 4), SHOCK_FORCE(22, 4),
//??? T4 //Endure T4
WARRIOR_3_1(23, 4), WARRIOR_3_2(24, 4), WARRIOR_3_3(25, 4), SUSTAINED_RETRIBUTION(23, 4), SHRUG_IT_OFF(24, 4), EVEN_THE_ODDS(25, 4),
//Mage T1 //Mage T1
EMPOWERING_MEAL(32), SCHOLARS_INTUITION(33), TESTED_HYPOTHESIS(34), BACKUP_BARRIER(35), EMPOWERING_MEAL(32), SCHOLARS_INTUITION(33), TESTED_HYPOTHESIS(34), BACKUP_BARRIER(35),

View File

@ -21,20 +21,138 @@
package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior; package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior;
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.Hero;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor; import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
import com.watabou.utils.Bundle;
public class Endure extends ArmorAbility { public class Endure extends ArmorAbility {
@Override @Override
protected void activate(ClassArmor armor, Hero hero, Integer target) { protected void activate(ClassArmor armor, Hero hero, Integer target) {
//TODO
Buff.prolong(hero, EndureTracker.class, 13f).setup(hero);
//TODO extend combo maybe?
hero.sprite.operate(hero.pos);
//TODO vfx/sfx?
armor.charge -= chargeUse(hero);
armor.updateQuickslot();
hero.spendAndNext(3f);
}
//TODO visual buff stuff
public static class EndureTracker extends FlavourBuff {
public boolean enduring;
public int damageBonus;
public int maxDmgTaken;
public int hitsLeft;
@Override
public int icon() {
return enduring ? BuffIndicator.NONE : BuffIndicator.AMOK;
} }
@Override
public float iconFadePercent() {
return Math.max(0, (10f - visualcooldown()) / 10f);
}
public void setup(Hero hero){
enduring = true;
maxDmgTaken = (int) (hero.HT * Math.pow(0.76f, hero.pointsInTalent(Talent.SHRUG_IT_OFF)));
damageBonus = 0;
hitsLeft = 0;
}
public int adjustDamageTaken(int damage){
if (enduring) {
damageBonus += damage/4;
return damage/2;
}
return damage;
}
public int enforceDamagetakenLimit(int damage){
if (damage >= maxDmgTaken) {
damage = maxDmgTaken;
maxDmgTaken = 0;
} else {
maxDmgTaken -= damage;
}
return damage;
}
public void endEnduring(){
if (!enduring){
return;
}
enduring = false;
damageBonus *= 1f + 0.1f*Dungeon.hero.pointsInTalent(Talent.SUSTAINED_RETRIBUTION);
int nearby = 0;
for (Char ch : Actor.chars()){
if (ch.alignment == Char.Alignment.ENEMY && Dungeon.level.distance(target.pos, ch.pos) <= 2){
nearby ++;
}
}
damageBonus *= 1f + (nearby*0.05f*Dungeon.hero.pointsInTalent(Talent.EVEN_THE_ODDS));
hitsLeft = 1+Dungeon.hero.pointsInTalent(Talent.SUSTAINED_RETRIBUTION);
damageBonus /= hitsLeft;
}
public int damageFactor(int damage){
if (enduring){
return damage;
} else {
int bonusDamage = damageBonus;
hitsLeft--;
if (hitsLeft <= 0){
detach();
}
return damage + bonusDamage;
}
}
public static String ENDURING = "enduring";
public static String DAMAGE_BONUS = "damage_bonus";
public static String MAX_DMG_TAKEN = "max_dmg_taken";
public static String HITS_LEFT = "hits_left";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
bundle.put(ENDURING, enduring);
bundle.put(DAMAGE_BONUS, damageBonus);
bundle.put(MAX_DMG_TAKEN, maxDmgTaken);
bundle.put(HITS_LEFT, hitsLeft);
}
@Override
public void restoreFromBundle(Bundle bundle) {
super.restoreFromBundle(bundle);
enduring = bundle.getBoolean(ENDURING);
damageBonus = bundle.getInt(DAMAGE_BONUS);
maxDmgTaken = bundle.getInt(ENDURING);
hitsLeft = bundle.getInt(HITS_LEFT);
}
};
@Override @Override
public Talent[] talents() { public Talent[] talents() {
return new Talent[]{Talent.WARRIOR_3_1, Talent.WARRIOR_3_2, Talent.WARRIOR_3_3, Talent.HEROIC_ENERGY}; return new Talent[]{Talent.SUSTAINED_RETRIBUTION, Talent.SHRUG_IT_OFF, Talent.EVEN_THE_ODDS, Talent.HEROIC_ENERGY};
} }
} }