From 25c61c493936e8f9f547eb44d651e1a4e1c8a23f Mon Sep 17 00:00:00 2001
From: Evan Debenham <Evan@ShatteredPixel.com>
Date: Wed, 10 Feb 2021 18:46:05 -0500
Subject: [PATCH] v0.9.2: implemented the assassin's reach talent

---
 .../assets/messages/actors/actors.properties  |  2 +
 .../actors/buffs/Preparation.java             | 38 ++++++++++++-------
 .../actors/hero/Talent.java                   |  4 +-
 3 files changed, 29 insertions(+), 15 deletions(-)

diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties
index ff2867062..f1620d952 100644
--- a/core/src/main/assets/messages/actors/actors.properties
+++ b/core/src/main/assets/messages/actors/actors.properties
@@ -396,6 +396,8 @@ actors.hero.talent.light_cloak.title=light cloak
 actors.hero.talent.light_cloak.desc=_+1:_ The Rogue can use his cloak of shadows when it is not equipped, but it recharges at _10% speed_.\n\n_+2:_ The Rogue can use his cloak of shadows when it is not equipped, but it recharges at _20% speed_.\n\n_+3:_ The Rogue can use his cloak of shadows when it is not equipped, but it recharges at _30% speed_.
 actors.hero.talent.enhanced_lethality.title=enhanced lethality
 actors.hero.talent.enhanced_lethality.desc=_+1:_ The Assassin can assassinate enemies below _4/12/25/60% health_ per level of preparation, up from 3/10/20/40%.\n\n_+2:_ The Assassin can assassinate enemies below _5/14/30/80% health_ per level of preparation, up from 3/10/20/40%.\n\n_+3:_ The Assassin can assassinate enemies below _6/16/35/100% health_ per level of preparation, up from 3/10/20/40%.
+actors.hero.talent.assassins_reach.title=assassin's reach
+actors.hero.talent.assassins_reach.desc=_+1:_ The Assassin's blink range per level of preparation is increased to _2/3/4/6 tiles_, from 1/2/3/4.\n\n_+2:_ The Assassin's blink range per level of preparation is increased to _3/5/6/8 tiles_, from 1/2/3/4.\n\n_+3:_ The Assassin's blink range per level of preparation is increased to _4/6/8/10 tiles_, from 1/2/3/4.
 actors.hero.talent.bounty_hunter.title=bounty hunter
 actors.hero.talent.bounty_hunter.desc=_+1:_ When the Assassin kills an enemy with a prepared strike they drop _10 extra gold_.\n\n_+2:_ When the Assassin kills an enemy with a prepared strike they drop _20 extra gold_.\n\n_+3:_ When the Assassin kills an enemy with a prepared strike they drop _30 extra gold_.
 actors.hero.talent.evasive_armor.title=evasive armor
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Preparation.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Preparation.java
index 35e112568..f65d64c03 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Preparation.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/Preparation.java
@@ -55,19 +55,19 @@ public class Preparation extends Buff implements ActionIndicator.Action {
 	}
 	
 	public enum AttackLevel{
-		LVL_1( 1, 0.15f, 1, 1),
-		LVL_2( 3, 0.30f, 1, 3),
-		LVL_3( 5, 0.45f, 2, 5),
-		LVL_4( 9, 0.60f, 3, 7);
+		LVL_1( 1, 0.15f, 1),
+		LVL_2( 3, 0.30f, 1),
+		LVL_3( 5, 0.45f, 2),
+		LVL_4( 9, 0.60f, 3);
 
 		final int turnsReq;
 		final float baseDmgBonus;
-		final int damageRolls, blinkDistance;
+		final int damageRolls;
 		
-		AttackLevel( int turns, float base, int rolls, int dist){
+		AttackLevel( int turns, float base, int rolls){
 			turnsReq = turns;
 			baseDmgBonus = base;
-			damageRolls = rolls; blinkDistance = dist;
+			damageRolls = rolls;
 		}
 
 		//1st index is prep level, 2nd is talent level
@@ -81,6 +81,18 @@ public class Preparation extends Buff implements ActionIndicator.Action {
 		public float KOThreshold(){
 			return KOThresholds[ordinal()][Dungeon.hero.pointsInTalent(Talent.ENHANCED_LETHALITY)];
 		}
+
+		//1st index is prep level, 2nd is talent level
+		private static final int[][] blinkRanges = new int[][]{
+				{1, 2, 3, 4},
+				{2, 3, 5, 6},
+				{3, 4, 6, 8},
+				{4, 6, 8, 10}
+		};
+
+		public int blinkDistance(){
+			return blinkRanges[ordinal()][Dungeon.hero.pointsInTalent(Talent.ASSASSINS_REACH)];
+		}
 		
 		public boolean canKO(Char defender){
 			if (defender.properties().contains(Char.Property.MINIBOSS)
@@ -118,7 +130,7 @@ public class Preparation extends Buff implements ActionIndicator.Action {
 	public boolean act() {
 		if (target.invisible > 0){
 			turnsInvis++;
-			if (AttackLevel.getLvl(turnsInvis).blinkDistance > 0 && target == Dungeon.hero){
+			if (AttackLevel.getLvl(turnsInvis).blinkDistance() > 0 && target == Dungeon.hero){
 				ActionIndicator.setAction(this);
 			}
 			spend(TICK);
@@ -199,8 +211,8 @@ public class Preparation extends Buff implements ActionIndicator.Action {
 			desc += " " + Messages.get(this, "desc_dmg_likely");
 		}
 		
-		if (lvl.blinkDistance > 0){
-			desc += "\n\n" + Messages.get(this, "desc_blink", lvl.blinkDistance);
+		if (lvl.blinkDistance() > 0){
+			desc += "\n\n" + Messages.get(this, "desc_blink", lvl.blinkDistance());
 		}
 		
 		desc += "\n\n" + Messages.get(this, "desc_invis_time", turnsInvis);
@@ -219,7 +231,7 @@ public class Preparation extends Buff implements ActionIndicator.Action {
 	public void restoreFromBundle(Bundle bundle) {
 		super.restoreFromBundle(bundle);
 		turnsInvis = bundle.getInt(TURNS);
-		if (AttackLevel.getLvl(turnsInvis).blinkDistance > 0){
+		if (AttackLevel.getLvl(turnsInvis).blinkDistance() > 0){
 			ActionIndicator.setAction(this);
 		}
 	}
@@ -277,7 +289,7 @@ public class Preparation extends Buff implements ActionIndicator.Action {
 				int attackPos = path == null ? -1 : path.get(path.size()-2);
 				
 				if (attackPos == -1 || Dungeon.hero.rooted ||
-						Dungeon.level.distance(attackPos, Dungeon.hero.pos) > lvl.blinkDistance){
+						Dungeon.level.distance(attackPos, Dungeon.hero.pos) > lvl.blinkDistance()){
 					GLog.w(Messages.get(Preparation.class, "out_of_reach"));
 					return;
 				}
@@ -300,7 +312,7 @@ public class Preparation extends Buff implements ActionIndicator.Action {
 		
 		@Override
 		public String prompt() {
-			return Messages.get(Preparation.class, "prompt", AttackLevel.getLvl(turnsInvis).blinkDistance);
+			return Messages.get(Preparation.class, "prompt", AttackLevel.getLvl(turnsInvis).blinkDistance());
 		}
 	};
 }
diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java
index 4624ad835..1d3c78436 100644
--- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java
+++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/Talent.java
@@ -95,7 +95,7 @@ public enum Talent {
 	//Rogue T3
 	LIGHT_CLOAK(73, 3), ROGUE_T3_2(74, 3),
 	//Assassin T3
-	ENHANCED_LETHALITY(75, 3), ASSASSIN_T3_2(76, 3), BOUNTY_HUNTER(77, 3),
+	ENHANCED_LETHALITY(75, 3), ASSASSINS_REACH(76, 3), BOUNTY_HUNTER(77, 3),
 	//Freerunner T3
 	EVASIVE_ARMOR(78, 3), PROJECTILE_MOMENTUM(79, 3), FREERUNNER_T3_3(80, 3),
 
@@ -470,7 +470,7 @@ public enum Talent {
 				Collections.addAll(tierTalents, SOUL_SIPHON, SOUL_EATER, NECROMANCERS_MINIONS);
 				break;
 			case ASSASSIN:
-				Collections.addAll(tierTalents, ENHANCED_LETHALITY, ASSASSIN_T3_2, BOUNTY_HUNTER);
+				Collections.addAll(tierTalents, ENHANCED_LETHALITY, ASSASSINS_REACH, BOUNTY_HUNTER);
 				break;
 			case FREERUNNER:
 				Collections.addAll(tierTalents, EVASIVE_ARMOR, PROJECTILE_MOMENTUM, FREERUNNER_T3_3);