v2.0.0: improved enchant/glyph empower logic, added runic blade ability

This commit is contained in:
Evan Debenham
2022-11-23 13:40:28 -05:00
parent f473f5144f
commit c6d7a06eac
13 changed files with 91 additions and 23 deletions

View File

@@ -592,7 +592,7 @@ actors.hero.talent.double_jump.desc=_+1:_ If the Warrior performs a second leap
actors.hero.talent.expanding_wave.title=expanding wave
actors.hero.talent.expanding_wave.desc=_+1:_ Shockwave's range is increased to _6 tiles_ from 5, and its width is increased to _75 degrees_ from 60.\n\n_+2:_ Shockwave's range is increased to _7 tiles_ from 5, and its width is increased to _90 degrees_ from 60.\n\n_+3:_ Shockwave's range is increased to _8 tiles_ from 5, and its width is increased to _105 degrees_ from 60.\n\n_+4:_ Shockwave's range is increased to _9 tiles_ from 5, and its width is increased to _120 degrees_ from 60.
actors.hero.talent.striking_wave.title=striking wave
actors.hero.talent.striking_wave.desc=_+1:_ Shockwave has a _30% chance_ to also use on-hit effects like enchantments and combo.\n\n_+2:_ Shockwave has a _60% chance_ to also use on-hit effects like enchantments and combo.\n\n_+3:_ Shockwave has a _90% chance_ to also use on-hit effects like enchantments and combo.\n\n_+4:_ Shockwave has a _100% chance_ to also use on-hit effects like enchantments and combo, and it triggers enchantments _20% more often_.
actors.hero.talent.striking_wave.desc=_+1:_ Shockwave has a _30% chance_ to also use on-hit effects like enchantments and combo.\n\n_+2:_ Shockwave has a _60% chance_ to also use on-hit effects like enchantments and combo.\n\n_+3:_ Shockwave has a _90% chance_ to also use on-hit effects like enchantments and combo.\n\n_+4:_ Shockwave has a _100% chance_ to also use on-hit effects like enchantments and combo, and it gives enchantments _+20% power_.
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 _40% 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.
@@ -776,7 +776,7 @@ actors.hero.talent.fan_of_blades.desc=_+1:_ Spectral blades can hit up to _1 add
actors.hero.talent.projecting_blades.title=projecting blades
actors.hero.talent.projecting_blades.desc=_+1:_ Spectral blades has _+25% accuracy_, and can penetrate up to _2 solid tiles_.\n\n_+2:_ Spectral blades has _+50% accuracy_, and can penetrate up to _4 solid tiles_.\n\n_+3:_ Spectral blades has _+75% accuracy_, and can penetrate up to _6 solid tiles_.\n\n_+4:_ Spectral blades has _+100% accuracy_, and can penetrate up to _8 solid tiles_.
actors.hero.talent.spirit_blades.title=spirit blades
actors.hero.talent.spirit_blades.desc=_+1:_ Spectral blades has a _30% chance_ to also use the enchantment on the spirit bow.\n\n_+2:_ Spectral blades has a _60% chance_ to also use the enchantment on the spirit bow.\n\n_+3:_ Spectral blades has a _90% chance_ to also use the enchantment on the spirit bow.\n\n_+4:_ Spectral blades has a _100% chance_ to also use the enchantment on the spirit bow, and it triggers each enchantment _10% more often_.
actors.hero.talent.spirit_blades.desc=_+1:_ Spectral blades has a _30% chance_ to also use the enchantment on the spirit bow.\n\n_+2:_ Spectral blades has a _60% chance_ to also use the enchantment on the spirit bow.\n\n_+3:_ Spectral blades has a _90% chance_ to also use the enchantment on the spirit bow.\n\n_+4:_ Spectral blades has a _100% chance_ to also use the enchantment on the spirit bow, and it gives each enchantment _+10% power_.
actors.hero.talent.growing_power.title=growing power
actors.hero.talent.growing_power.desc=_+1:_ The attack and movespeed boosts from nature's power are increased to _38% and 125%_, from 33% and 100%.\n\n_+2:_ The attack and movespeed boosts from nature's power are increased to _42% and 150%_, from 33% and 100%.\n\n_+3:_ The attack and movespeed boosts from nature's power are increased to _46% and 175%_, from 33% and 100%.\n\n_+4:_ The attack and movespeed boosts from nature's power are increased to _50% and 200%_, from 33% and 100%.

View File

@@ -1592,6 +1592,8 @@ items.weapon.melee.roundshield.desc=This large shield effectively blocks attacks
items.weapon.melee.runicblade.name=runic blade
items.weapon.melee.runicblade.stats_desc=This weapon benefits more from upgrades.
items.weapon.melee.runicblade.ability_name=runic slash
items.weapon.melee.runicblade.ability_desc=The duelist can perform a _runic slash_ with a runic blade. This attack is guaranteed to hit and has +200% enchantment power.
items.weapon.melee.runicblade.desc=A mysterious weapon from a distant land, with a bright blue blade.
items.weapon.melee.sai.name=sai

View File

@@ -40,7 +40,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ChampionEnemy;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Charm;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Chill;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Corrosion;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Corruption;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Cripple;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Doom;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Dread;
@@ -84,19 +83,17 @@ import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Potential;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.exotic.PotionOfCleansing;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfArcana;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfElements;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRetribution;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ScrollOfChallenge;
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ScrollOfPsionicBlast;
import com.shatteredpixel.shatteredpixeldungeon.items.stones.StoneOfAggression;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfFireblast;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfFrost;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfLightning;
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfLivingEarth;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Blazing;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Blocking;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Grim;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Kinetic;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Shocking;
@@ -682,7 +679,7 @@ public abstract class Char extends Actor {
if (((Char) src).buff(Kinetic.KineticTracker.class) != null){
int dmgToAdd = -HP;
dmgToAdd -= ((Char) src).buff(Kinetic.KineticTracker.class).conservedDamage;
dmgToAdd = Math.round(dmgToAdd * RingOfArcana.enchantPowerMultiplier((Char) src));
dmgToAdd = Math.round(dmgToAdd * Weapon.Enchantment.genericProcChanceMultiplier((Char) src));
if (dmgToAdd > 0) {
Buff.affect((Char) src, Kinetic.ConservedDamage.class).setBonus(dmgToAdd);
}

View File

@@ -31,6 +31,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Thief;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Brimstone;
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.TimekeepersHourglass;
import com.shatteredpixel.shatteredpixeldungeon.items.food.ChargrilledMeat;
@@ -179,7 +180,7 @@ public class Burning extends Buff implements Hero.Doom {
&& ((Hero) ch).belongings.armor() != null
&& ((Hero) ch).belongings.armor().hasGlyph(Brimstone.class, ch)){
//has a 2*boost/50% chance to generate 1 shield per turn, to a max of 4x boost
float shieldChance = 2*(RingOfArcana.enchantPowerMultiplier(ch) - 1f);
float shieldChance = 2*(Armor.Glyph.genericProcChanceMultiplier(ch) - 1f);
int shieldCap = Math.round(shieldChance*4f);
if (shieldCap > 0 && Random.Float() < shieldChance){
Barrier barrier = Buff.affect(ch, Barrier.class);

View File

@@ -354,9 +354,9 @@ public class Armor extends EquipableItem {
break;
}
}
if (!enemyNear) speed *= (1.2f + 0.04f * buffedLvl()) * RingOfArcana.enchantPowerMultiplier(owner);
if (!enemyNear) speed *= (1.2f + 0.04f * buffedLvl()) * glyph.procChanceMultiplier(owner);
} else if (hasGlyph(Flow.class, owner) && Dungeon.level.water[owner.pos]){
speed *= (2f + 0.25f*buffedLvl()) * RingOfArcana.enchantPowerMultiplier(owner);
speed *= (2f + 0.25f*buffedLvl()) * glyph.procChanceMultiplier(owner);
}
if (hasGlyph(Bulk.class, owner) &&
@@ -372,7 +372,7 @@ public class Armor extends EquipableItem {
public float stealthFactor( Char owner, float stealth ){
if (hasGlyph(Obfuscation.class, owner)){
stealth += (1 + buffedLvl()/3f) * RingOfArcana.enchantPowerMultiplier(owner);
stealth += (1 + buffedLvl()/3f) * glyph.procChanceMultiplier(owner);
}
return stealth;
@@ -648,6 +648,10 @@ public class Armor extends EquipableItem {
public abstract int proc( Armor armor, Char attacker, Char defender, int damage );
protected float procChanceMultiplier( Char defender ){
return genericProcChanceMultiplier( defender );
}
public static float genericProcChanceMultiplier( Char defender ){
return RingOfArcana.enchantPowerMultiplier(defender);
}

View File

@@ -118,8 +118,8 @@ public class AntiMagic extends Armor.Glyph {
public static int drRoll( Char ch, int level ){
return Random.NormalIntRange(
Math.round(level * RingOfArcana.enchantPowerMultiplier(ch)),
Math.round((3 + (level*1.5f)) * RingOfArcana.enchantPowerMultiplier(ch)));
Math.round(level * genericProcChanceMultiplier(ch)),
Math.round((3 + (level*1.5f)) * genericProcChanceMultiplier(ch)));
}
@Override

View File

@@ -42,7 +42,7 @@ public class Camouflage extends Armor.Glyph {
}
public static void activate(Char ch, int level){
Buff.prolong(ch, Invisibility.class, Math.round((3 + level/2f)* RingOfArcana.enchantPowerMultiplier(ch)));
Buff.prolong(ch, Invisibility.class, Math.round((3 + level/2f)* genericProcChanceMultiplier(ch)));
if ( Dungeon.level.heroFOV[ch.pos] ) {
Sample.INSTANCE.play( Assets.Sounds.MELD );
}

View File

@@ -39,7 +39,7 @@ public class Stone extends Armor.Glyph {
float accuracy = attacker.attackSkill(defender);
testing = false;
evasion *= RingOfArcana.enchantPowerMultiplier(defender);
evasion *= genericProcChanceMultiplier(defender);
float hitChance;
if (evasion >= accuracy){

View File

@@ -77,7 +77,7 @@ public class Viscosity extends Glyph {
int level = Math.max( 0, this.level );
float percent = (level+1)/(float)(level+6);
percent *= RingOfArcana.enchantPowerMultiplier(target);
percent *= genericProcChanceMultiplier(target);
int amount;
if (percent > 1f){

View File

@@ -53,6 +53,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Projec
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Shocking;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Unstable;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Vampiric;
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.RunicBlade;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSprite;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
@@ -210,7 +211,7 @@ abstract public class Weapon extends KindOfWeapon {
@Override
public int reachFactor(Char owner) {
if (hasEnchant(Projecting.class, owner)){
return RCH + Math.round(RingOfArcana.enchantPowerMultiplier(owner));
return RCH + Math.round(enchantment.procChanceMultiplier(owner));
} else {
return RCH;
}
@@ -368,12 +369,20 @@ abstract public class Weapon extends KindOfWeapon {
public abstract int proc( Weapon weapon, Char attacker, Char defender, int damage );
protected float procChanceMultiplier( Char attacker ){
return genericProcChanceMultiplier( attacker );
}
public static float genericProcChanceMultiplier( Char attacker ){
float multi = RingOfArcana.enchantPowerMultiplier(attacker);
Berserk rage = attacker.buff(Berserk.class);
if (rage != null) {
multi = rage.enchantFactor(multi);
}
if (attacker.buff(RunicBlade.RunicSlashTracker.class) != null){
multi += 2f;
}
if (attacker.buff(Talent.SpiritBladesTracker.class) != null
&& ((Hero)attacker).pointsInTalent(Talent.SPIRIT_BLADES) == 4){
multi += 0.1f;

View File

@@ -46,13 +46,18 @@ public class Blazing extends Weapon.Enchantment {
if (Random.Float() < procChance) {
float powerMulti = Math.max(1f, procChance);
if (defender.buff(Burning.class) != null){
if (defender.buff(Burning.class) == null){
Buff.affect(defender, Burning.class).reignite(defender, 8f);
powerMulti -= 1;
}
if (powerMulti > 0){
int burnDamage = Random.NormalIntRange( 1, 3 + Dungeon.scalingDepth()/4 );
defender.damage( Math.round(burnDamage * 0.67f * powerMulti), this );
} else {
Buff.affect(defender, Burning.class).reignite(defender, 8f);
burnDamage = Math.round(burnDamage * 0.67f * powerMulti);
if (burnDamage > 0) {
defender.damage(burnDamage, this);
}
}
defender.sprite.emitter().burst( FlameParticle.FACTORY, level + 1 );

View File

@@ -22,7 +22,17 @@
package com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee;
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.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Callback;
public class RunicBlade extends MeleeWeapon {
@@ -42,4 +52,44 @@ public class RunicBlade extends MeleeWeapon {
return 5*(tier) + //20 base, down from 25
Math.round(lvl*(tier+2)); //+6 per level, up from +5
}
@Override
public String targetingPrompt() {
return Messages.get(this, "prompt");
}
@Override
protected void duelistAbility(Hero hero, Integer target) {
if (target == null) {
return;
}
Char enemy = Actor.findChar(target);
if (enemy == null || enemy == hero || hero.isCharmedBy(enemy) || !Dungeon.level.heroFOV[target]) {
GLog.w(Messages.get(this, "ability_no_target"));
return;
}
//we apply here because of projecting
RunicSlashTracker tracker = Buff.affect(hero, RunicSlashTracker.class);
if (!hero.canAttack(enemy)){
GLog.w(Messages.get(this, "ability_bad_position"));
tracker.detach();
return;
}
hero.sprite.attack(enemy.pos, new Callback() {
@Override
public void call() {
hero.attack(enemy, 1f, 0, Char.INFINITE_ACCURACY);
tracker.detach();
onAbilityUsed(hero);
Sample.INSTANCE.play(Assets.Sounds.HIT_STRONG);
hero.spendAndNext(hero.attackDelay());
}
});
}
public static class RunicSlashTracker extends FlavourBuff{};
}

View File

@@ -166,7 +166,7 @@ abstract public class MissileWeapon extends Weapon {
if (projecting
&& (Dungeon.level.passable[dst] || Dungeon.level.avoid[dst])
&& Dungeon.level.distance(user.pos, dst) <= Math.round(4 * RingOfArcana.enchantPowerMultiplier(user))){
&& Dungeon.level.distance(user.pos, dst) <= Math.round(4 * Enchantment.genericProcChanceMultiplier(user))){
return dst;
} else {
return super.throwPos(user, dst);