From af7632f9c73284c76e5c55de1185e55f33b4a515 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Thu, 13 Feb 2025 16:36:32 -0500 Subject: [PATCH] v3.0.0: implemented the base power of many ability --- core/src/main/assets/interfaces/buffs.png | Bin 1846 -> 7846 bytes .../main/assets/interfaces/large_buffs.png | Bin 4161 -> 13152 bytes .../assets/messages/actors/actors.properties | 17 +- .../assets/messages/items/items.properties | 1 + .../shatteredpixeldungeon/Dungeon.java | 4 +- .../shatteredpixeldungeon/actors/Char.java | 37 +- .../actors/buffs/PrismaticGuard.java | 43 ++- .../hero/abilities/cleric/PowerOfMany.java | 335 ++++++++++++++++++ .../actors/mobs/Mob.java | 11 +- .../actors/mobs/npcs/PrismaticImage.java | 2 +- .../items/wands/WandOfLivingEarth.java | 45 ++- .../journal/Bestiary.java | 3 +- .../shatteredpixeldungeon/levels/Level.java | 4 +- .../ui/BuffIndicator.java | 1 + 14 files changed, 481 insertions(+), 22 deletions(-) diff --git a/core/src/main/assets/interfaces/buffs.png b/core/src/main/assets/interfaces/buffs.png index 59b3120ca196f09a0a41e400def7e98b34412733..f1e5d34c36c8747b33ef6b11459feaa3c3099ac3 100644 GIT binary patch literal 7846 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 XHUpod55EKtoPddexqiN`%jy3Dcsk#^ delta 1842 zcmV-22hI4VJ+=;z8Gi!+0089(k4*po0W45VR7JRAxMpT%|0)3gsx$xp|Nq-%@^cu> z3=9B(RsaA1GfV&gRHgt}CYhOfM`WF|v$FsI0PmB||HS40|7L)IfPii@@}Oq&-!03lbGFPY`fTun9~|1&c^MNMTNW-bjbHY*^^%*>hpG)+A&^Ky&-%-zh>5x0>? z%m4sVQc`$5HgZ2)h(iXtS{zw2ApidWz;>n0ow%XW&zYH-tZ`$q>Hnd{kzN{rlPJmm z002}pXMJ^XDt{U@h-xmGA0Iy_O?Pr3>s`M4!YYNs<&}h$W7AV#pJb zFN`rF&*X)?k~d<=JIP3%M^RChWf252V<1o^Dp1!o1R4=(tZTczYn>l(25&ME$y8t* zAuvs|h?p7$fn`~Oz`Cv~uzd;aLEs1i=XG7@j{x$cA}WhGHpb`=R4D}bC@a=tT!-Y& zc|G1B41dGtqh+434C+x}+cp)rcL*F>$PfJ^P)6FZp+H(yFfhUru^86}oYxZsB>QNu zESTF!q99y#eg`il9foC8#keNLxG}Gjn3Id+S}itg&%1k&HyK%-T>nL=}*sq6Ex85%?_SoL7)?h0<56ajr?v1l);bA zK;tcFYT^uVrheTmU_Jz}ARsh^KX(gU^oU;3Clb*wN@73^3U?pE9u_t6R*Z_!tGoNpIi8WZ&cj1kyBxz`Hbk2Z8ah2A&WKOa+1Ip=k)r;Qq`+fmuR< zISR}#EG*1_HtLKw0RdP@AWTuCz$EEQ(#*0n=}-IlDD`qdAS~oh!N8|SM@Of9_>*B6 z3@^SXi*Lc~+gxCN;lqay3-gXx3Vi(Ncz=cf*24zI$Rh#BLZE*M4MYJozeyKm*PI^J4>i{S+XafhX7!s5gKKU<0+q z8XI7~1Y!ev{azQ~g96PgAPT@hLx}u10~~@BL&$sxumBywqZwG_3B(zgBl!#=u7amV`0Nh^R`7aG?2ij}IJQ^)>A9=_i5pAYcyk1^HHmz{cjr z##Rt8g5ReYx1_VF@>!*+vkC)L0Dm!qAhQjNKbm!ikAz%6`4FH18dzOhWdr=7%>3;g z2*_UdkojpfDevy>?n=PIN-_+5mNZo=d{jG@mtl}MKn)8U4&5(Fw@ne#b&djSYx`?! ze*e?d$O!UB+;sO?V`v~_0|y6(2NGaHV*?NX)zF#h&!^z2H#Xp!0c4hA1AqDeo|@X$ z3_u_r0rIoZ!0zsz1Q2ge8)rZb=x?g-$7Vnc=+xs3NCyo`00k&t4WwZPHa0dTpbyf< zThP&g8PE?({|&cb3IqXRd_2AdnK%;7!c|vExTr-){N<0+ES`y)U@Yo67WV?{ClEM2 zJ%zwJfxwxaK|t?48e?RAG=IatFhT*GtOTs~k(jDO>T0XGz|u<#av4u9CdRcrvn2AY{4 z8|Xzo1V*taV5*t z%rBv8-lK5VG0Zind9Yy#<%8J3GoHW$0gl1(1v&m3ZUN%U;P?V}APAU9ehC?g-^ZWa z6Bl3qY9!#d63Fn#_!PzV$P gg+L)t2owU}1KxS(87&m5h5!Hn07*qoM6N<$f-H446#xJL diff --git a/core/src/main/assets/interfaces/large_buffs.png b/core/src/main/assets/interfaces/large_buffs.png index 19fe65a529d729dc4c818b558d2d9e0d12d56e50..244aa5769702272af4467a62fec581ed6a8d52f2 100644 GIT binary patch literal 13152 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 literal 4161 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 A%m4rY diff --git a/core/src/main/assets/messages/actors/actors.properties b/core/src/main/assets/messages/actors/actors.properties index 9cedfd0f1..952c48e84 100644 --- a/core/src/main/assets/messages/actors/actors.properties +++ b/core/src/main/assets/messages/actors/actors.properties @@ -370,6 +370,7 @@ actors.buffs.preparation.assassinated=assassinated actors.buffs.prismaticguard.name=prismatic Guard actors.buffs.prismaticguard.desc=You are being guarded by a prismatic image which is currently inactive. When enemies are present the prismatic image will spring to action and protect you!\n\nWhile inactive, the prismatic image will steadily recover from any damage it has taken.\n\nCurrent HP: %d/%d. +actors.buffs.prismaticguard.desc_many=This prismatic image is also benefitting from Power of Many. Turns Remaining: %d. actors.buffs.recharging.name=recharging actors.buffs.recharging.desc=Energy is coursing through you, improving the rate that your wands and staffs charge.\n\nEach turn this buff will increase current charge by one quarter, in addition to regular recharge.\n\nTurns of recharging remaining: %s. @@ -577,8 +578,20 @@ actors.hero.abilities.cleric.trinity$wnditemconfirm.body=Assign to body form actors.hero.abilities.cleric.trinity$wnditemconfirm.mind=Assign to mind form actors.hero.abilities.cleric.trinity$wnditemconfirm.spirit=Assign to spirit form actors.hero.abilities.cleric.powerofmany.name=power of many +actors.hero.abilities.cleric.powerofmany.prompt_default=Choose an ally or location +actors.hero.abilities.cleric.powerofmany.prompt_ally=Direct your light ally +actors.hero.abilities.cleric.powerofmany.ally_exists=You already have an empowered ally. +actors.hero.abilities.cleric.powerofmany.no_vision=You can't target a location you can't see. +actors.hero.abilities.cleric.powerofmany.only_allies=You can only empower allies. actors.hero.abilities.cleric.powerofmany.short_desc=The Cleric channels the _Power of Many_, empowering an existing ally or creating a new one. -actors.hero.abilities.cleric.powerofmany.desc=The Cleric channels the _Power of Many_, which either empowers an existing ally or creates a new empowered one for 100 turns.\n\nWhile empowered by Power of Many, any ally deals +25% damage, takes -25% damage, and shares their vision with the Cleric. They also gain a burst of 25 shielding when the ability is used.\n\nThe Cleric also gains three new spells that can only be cast with an empowered ally. Power of Many won't end while one of these spells is active. +actors.hero.abilities.cleric.powerofmany.desc=The Cleric channels the _Power of Many_, which either empowers an existing ally or creates a new empowered one for 100 turns. Targeting an empty space creates a new ally.\n\nWhile empowered by Power of Many, any ally deals +25% damage, takes -25% damage, and shares their vision with the Cleric. They also gain 25 shielding when the ability is used.\n\nThe Cleric also gains three new spells that can only be cast with an empowered ally. Power of Many won't end while one of these spells is active. +actors.hero.abilities.cleric.powerofmany$powerbuff.name=power of many +actors.hero.abilities.cleric.powerofmany$powerbuff.desc=This ally has been empowered by Power of Many, granting them +25%% damage dealt and -25%% damage taken. They will also share their vision range with the Cleric, and can benefit from power of many spells.\n\nPower of Many will persist when allies such as prismatic images hide away, but its duration will still count down.\n\nTurns Remaining: %s. +actors.hero.abilities.cleric.powerofmany$lightally.name=light ally +actors.hero.abilities.cleric.powerofmany$lightally.direct_defend=Your ally moves to that position. +actors.hero.abilities.cleric.powerofmany$lightally.direct_follow=Your ally moves to follow you. +actors.hero.abilities.cleric.powerofmany$lightally.direct_attack=Your ally moves to attack! +actors.hero.abilities.cleric.powerofmany$lightally.desc=A copy of one of the Cleric's adventuring companions, made out of solid light. While it has the shape of another hero, it does not have any of their unique abilities. This ally will persist for as long as Power of Many is applied to them.\n\nThis ally can be directed at no cost by re-using the Power of Many armor ability. actors.hero.abilities.ratmogrify.name=ratmogrify @@ -1228,7 +1241,7 @@ actors.hero.talent.beaming_ray.desc=The Cleric can cast _Beaming Ray_ from an em 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 -actors.hero.talent.stasis.desc=The Cleric can cast _Stasis_ on an empowered ally at the cost of 1 charge. Stasis temporarily removes the ally from the dungeon and preserves the remaining time on all buffs, including Power of Many itself. The ally will reappear next to you when the effect ends. Stasis can be re-cast at no cost to end the effect early.\n\n_+1:_ Stasis lasts for a max of _40 turns._\n\n_+2:_ Stasis lasts for a max of _60 turns._\n\n_+3:_ Stasis lasts for a max of _80 turns._\n\n_+4:_ Stasis lasts for a max of _100 turns._\n\nThe Cleric can also cast Beaming Ray when an ally in in stasis to resummon them, or cast Life Link to pre-emptively apply the effect. An ally in stasis still benefits from life link if relevant. +actors.hero.talent.stasis.desc=The Cleric can cast _Stasis_ on an empowered ally at the cost of 1 charge. Stasis temporarily removes the ally from the dungeon and preserves the remaining time on all buffs, including Power of Many. The ally will reappear next to you when the effect ends. Stasis can be re-cast at no cost to end the effect early.\n\n_+1:_ Stasis lasts for a max of _40 turns._\n\n_+2:_ Stasis lasts for a max of _60 turns._\n\n_+3:_ Stasis lasts for a max of _80 turns._\n\n_+4:_ Stasis lasts for a max of _100 turns._\n\nThe Cleric can also cast Beaming Ray when an ally is in stasis to resummon them, or cast Life Link to pre-emptively apply its effect. An ally in stasis still benefits from life link if relevant. #universal diff --git a/core/src/main/assets/messages/items/items.properties b/core/src/main/assets/messages/items/items.properties index bdbd27209..4bfa0cab4 100644 --- a/core/src/main/assets/messages/items/items.properties +++ b/core/src/main/assets/messages/items/items.properties @@ -1540,6 +1540,7 @@ items.wands.wandoflivingearth.bmage_desc=When _the Battlemage_ strikes an enemy items.wands.wandoflivingearth.eleblast_desc=An elemental blast with a staff of living earth deals 50% damage, and heals an active earthen guardian for each enemy hit. items.wands.wandoflivingearth$rockarmor.name=rock armor items.wands.wandoflivingearth$rockarmor.desc=Magical rocks are surrounding your body, when you are attacked they will attempt to block for you, and will reduce the damage you take by 50%%. Each damage blocked scrapes away some of the rock however.\n\nRemaining Armor: %1$d.\n\nIf enough rock is built around you, the next zap from your wand of living earth will cause the rocks to form up into a guardian which will fight with you.\n\nArmor needed for Guardian: %2$d. +items.wands.wandoflivingearth$rockarmor.desc_many=This earthen guardian is also benefitting from Power of Many. Turns Remaining: %d. items.wands.wandoflivingearth$earthguardian.name=earthen guardian items.wands.wandoflivingearth$earthguardian.desc=The rocks from your wand of living earth have formed into a protective earthen guardian! This rocky protector will attack nearby enemies, which will force them to attack the guardian instead of you. When all nearby threats are gone, the guardian will re-form around you, and will return when you next use your wand. items.wands.wandoflivingearth$earthguardian.wand_info=The guardian's defensive power is tied to the level of your wand. It currently blocks _%1$d-%2$d damage._ diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java index 876d08534..985568113 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Dungeon.java @@ -34,6 +34,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.RevealedArea; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror; 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.hero.abilities.huntress.SpiritHawk; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.DivineSense; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic; @@ -1002,7 +1003,8 @@ public class Dungeon { for (Char ch : Actor.chars()){ if (ch instanceof WandOfWarding.Ward || ch instanceof WandOfRegrowth.Lotus - || ch instanceof SpiritHawk.HawkAlly){ + || ch instanceof SpiritHawk.HawkAlly + || ch.buff(PowerOfMany.PowerBuff.class) != null){ x = ch.pos % level.width(); y = ch.pos / level.width(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java index 36c831c59..34dc23dfb 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/Char.java @@ -77,6 +77,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Challenge; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.DeathMark; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.warrior.Endure; @@ -425,6 +426,10 @@ public abstract class Char extends Actor { dmg *= 1.5f; } + if (buff( PowerOfMany.PowerBuff.class) != null){ + dmg *= 1.25f; + } + for (ChampionEnemy buff : buffs(ChampionEnemy.class)){ dmg *= buff.meleeDamageFactor(); } @@ -451,6 +456,10 @@ public abstract class Char extends Actor { dmg *= 0.925f - 0.075f*Dungeon.hero.pointsInTalent(Talent.AURA_OF_PROTECTION); } + if (enemy.buff(PowerOfMany.PowerBuff.class) != null){ + dmg *= 0.75f; + } + if (enemy.buff(MonkEnergy.MonkAbility.Meditate.MeditateResistance.class) != null){ dmg *= 0.2f; } @@ -777,12 +786,18 @@ public abstract class Char extends Actor { } } + //temporarily assign to a float to avoid rounding a bunch + float damage = dmg; + //if dmg is from a character we already reduced it in defenseProc if (!(src instanceof Char)) { if (Dungeon.hero.alignment == alignment && Dungeon.level.distance(pos, Dungeon.hero.pos) <= 2 && Dungeon.hero.buff(AuraOfProtection.AuraBuff.class) != null) { - dmg *= 0.925f - 0.075f*Dungeon.hero.pointsInTalent(Talent.AURA_OF_PROTECTION); + damage *= 0.925f - 0.075f*Dungeon.hero.pointsInTalent(Talent.AURA_OF_PROTECTION); + } + if (buff(PowerOfMany.PowerBuff.class) != null){ + damage *= 0.75f; } } @@ -805,10 +820,10 @@ public abstract class Char extends Actor { Buff.detach(this, MagicalSleep.class); } if (this.buff(Doom.class) != null && !isImmune(Doom.class)){ - dmg *= 1.67f; + damage *= 1.67f; } if (alignment != Alignment.ALLY && this.buff(DeathMark.DeathMarkTracker.class) != null){ - dmg *= 1.25f; + damage *= 1.25f; } if (buff(Sickle.HarvestBleedTracker.class) != null){ @@ -827,15 +842,19 @@ public abstract class Char extends Actor { } } - for (ChampionEnemy buff : buffs(ChampionEnemy.class)){ - dmg = (int) Math.ceil(dmg * buff.damageTakenFactor()); - } - Class srcClass = src.getClass(); if (isImmune( srcClass )) { - dmg = 0; + damage = 0; } else { - dmg = Math.round( dmg * resist( srcClass )); + damage *= resist( srcClass ); + } + + dmg = Math.round(damage); + + //we ceil these specifically to favor the player vs. champ dmg reduction + // most important vs. giant champions in the earlygame + for (ChampionEnemy buff : buffs(ChampionEnemy.class)){ + dmg = (int) Math.ceil(dmg * buff.damageTakenFactor()); } //TODO improve this when I have proper damage source logic diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PrismaticGuard.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PrismaticGuard.java index 6a7ed4608..56f451b27 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PrismaticGuard.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/buffs/PrismaticGuard.java @@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs; import com.shatteredpixel.shatteredpixeldungeon.Dungeon; import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.PrismaticImage; import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation; @@ -41,6 +42,8 @@ public class PrismaticGuard extends Buff { } private float HP; + + private float powerOfManyTurns = 0; @Override public boolean act() { @@ -72,6 +75,9 @@ public class PrismaticGuard extends Buff { if (bestPos != -1) { PrismaticImage pris = new PrismaticImage(); pris.duplicate(hero, (int)Math.floor(HP) ); + if (powerOfManyTurns > 0){ + Buff.affect(pris, PowerOfMany.PowerBuff.class, powerOfManyTurns); + } pris.state = pris.HUNTING; GameScene.add(pris, 1); ScrollOfTeleportation.appear(pris, bestPos); @@ -86,16 +92,32 @@ public class PrismaticGuard extends Buff { spend(TICK); } - LockedFloor lock = target.buff(LockedFloor.class); if (HP < maxHP() && Regeneration.regenOn()){ HP += 0.1f; } + if (powerOfManyTurns > 0){ + powerOfManyTurns--; + if (powerOfManyTurns <= 0){ + powerOfManyTurns = 0; + BuffIndicator.refreshHero(); + } + } return true; } public void set( int HP ){ this.HP = HP; + powerOfManyTurns = 0; + } + + public void set( PrismaticImage img){ + this.HP = img.HP; + if (img.buff(PowerOfMany.PowerBuff.class) != null){ + powerOfManyTurns = img.buff(PowerOfMany.PowerBuff.class).cooldown()+1; + } else { + powerOfManyTurns = 0; + } } public int maxHP(){ @@ -105,6 +127,10 @@ public class PrismaticGuard extends Buff { public static int maxHP( Hero hero ){ return 10 + (int)Math.floor(hero.lvl * 2.5f); //half of hero's HP } + + public boolean isEmpowered(){ + return powerOfManyTurns > 0; + } @Override public int icon() { @@ -113,7 +139,11 @@ public class PrismaticGuard extends Buff { @Override public void tintIcon(Image icon) { - icon.hardlight(1f, 1f, 2f); + if (isEmpowered()){ + icon.hardlight(3f, 3f, 2f); + } else { + icon.hardlight(1f, 1f, 2f); + } } @Override @@ -128,20 +158,27 @@ public class PrismaticGuard extends Buff { @Override public String desc() { - return Messages.get(this, "desc", (int)HP, maxHP()); + String desc = Messages.get(this, "desc", (int)HP, maxHP()); + if (isEmpowered()){ + desc += "\n\n" + Messages.get(this, "desc_many", (int)powerOfManyTurns); + } + return desc; } private static final String HEALTH = "hp"; + private static final String POWER_TURNS = "power_turns"; @Override public void storeInBundle(Bundle bundle) { super.storeInBundle(bundle); bundle.put(HEALTH, HP); + bundle.put(POWER_TURNS, powerOfManyTurns); } @Override public void restoreFromBundle(Bundle bundle) { super.restoreFromBundle(bundle); HP = bundle.getFloat(HEALTH); + powerOfManyTurns = bundle.getFloat(POWER_TURNS); } } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/PowerOfMany.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/PowerOfMany.java index 514ee91f5..ed86bd2b4 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/PowerOfMany.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/hero/abilities/cleric/PowerOfMany.java @@ -21,17 +21,140 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric; +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.AllyBuff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barrier; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility; +import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.PrismaticGuard; 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.mobs.Mob; +import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.DirectableAlly; +import com.shatteredpixel.shatteredpixeldungeon.effects.Speck; +import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShaftParticle; import com.shatteredpixel.shatteredpixeldungeon.items.armor.ClassArmor; +import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation; +import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfLivingEarth; +import com.shatteredpixel.shatteredpixeldungeon.messages.Messages; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite; +import com.shatteredpixel.shatteredpixeldungeon.sprites.HeroSprite; +import com.shatteredpixel.shatteredpixeldungeon.sprites.MobSprite; +import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator; import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon; +import com.shatteredpixel.shatteredpixeldungeon.utils.GLog; +import com.watabou.noosa.TextureFilm; +import com.watabou.noosa.audio.Sample; +import com.watabou.utils.Bundle; +import com.watabou.utils.Random; public class PowerOfMany extends ArmorAbility { + @Override + public float chargeUse(Hero hero) { + if (getPoweredAlly() instanceof LightAlly){ + return 0; + } + return super.chargeUse(hero); + } + + @Override + public String targetingPrompt() { + Char ally = getPoweredAlly(); + + boolean allyExists = ally != null; + + if (Dungeon.hero.buff(PrismaticGuard.class) != null + && Dungeon.hero.buff(PrismaticGuard.class).isEmpowered()){ + allyExists = true; + } + + if (Dungeon.hero.buff(WandOfLivingEarth.RockArmor.class) != null + && Dungeon.hero.buff(WandOfLivingEarth.RockArmor.class).isEmpowered()){ + allyExists = true; + } + + if (ally instanceof LightAlly){ + return Messages.get(this, "prompt_ally"); + } else if (!allyExists){ + return Messages.get(this, "prompt_default"); + } else { + return null; + } + } + @Override protected void activate(ClassArmor armor, Hero hero, Integer target) { + Char ally = getPoweredAlly(); + + boolean allyExists = ally != null; + + if (hero.buff(PrismaticGuard.class) != null + && hero.buff(PrismaticGuard.class).isEmpowered()){ + allyExists = true; + } + + if (hero.buff(WandOfLivingEarth.RockArmor.class) != null + && hero.buff(WandOfLivingEarth.RockArmor.class).isEmpowered()){ + allyExists = true; + } + + if (ally instanceof LightAlly){ + if (target == null){ + return; + } else { + ((LightAlly) ally).directTocell(target); + } + } else if (allyExists) { + GLog.w( Messages.get(this, "ally_exists")); + } else { + if (target == null){ + return; + } + + if (!Dungeon.level.heroFOV[target]){ + GLog.w(Messages.get(this, "no_vision")); + return; + } + + //pre-calculate as cost becomes 0 if light ally starts to exist + float chargeUse = chargeUse(hero); + + Char ch = Actor.findChar(target); + if (ch != null){ + if (ch.alignment != Char.Alignment.ALLY || ch == Dungeon.hero){ + GLog.w(Messages.get(this, "only_allies")); + return; + } + } else { + ch = new LightAlly(hero.lvl); + ch.pos = target; + GameScene.add((Mob) ch); + ScrollOfTeleportation.appear(ch, ch.pos); + } + + Buff.affect(ch, PowerBuff.class, 100f); + Buff.affect(ch, Barrier.class).setShield(25); + + armor.charge -= chargeUse; + armor.updateQuickslot(); + + hero.sprite.zap(target); + Sample.INSTANCE.play(Assets.Sounds.CHARGEUP); + + Invisibility.dispel(); + hero.spendAndNext(Actor.TICK); + + } + } @Override @@ -44,4 +167,216 @@ public class PowerOfMany extends ArmorAbility { return new Talent[]{Talent.BEAMING_RAY, Talent.LIFE_LINK, Talent.STASIS, Talent.HEROIC_ENERGY}; } + private static Char getPoweredAlly(){ + for (Char ch : Actor.chars()){ + if (ch.buff(PowerBuff.class) != null){ + return ch; + } + } + return null; + } + + public static class PowerBuff extends FlavourBuff { + + public static float DURATION = 100f; + + { + type = buffType.POSITIVE; + announced = true; + } + + @Override + public int icon() { + return BuffIndicator.MANY_POWER; + } + + @Override + public float iconFadePercent() { + return Math.max(0, (DURATION - visualcooldown()) / DURATION); + } + + @Override + public void fx(boolean on) { + if (on) target.sprite.add(CharSprite.State.GLOWING); + else target.sprite.remove(CharSprite.State.GLOWING); + } + + @Override + public void detach() { + super.detach(); + if (target instanceof LightAlly){ + target.die(this); + } + Dungeon.observe(); + GameScene.updateFog(); + } + } + + public static class LightAlly extends DirectableAlly { + + { + spriteClass = LightAllySprite.class; + + HP = HT = 80; + + immunities.add(AllyBuff.class); + + properties.add(Property.INORGANIC); + } + + HeroClass cls; + + public LightAlly(){ + super(); + cls = HeroClass.values()[Random.Int(5)]; + } + + public LightAlly(int heroLevel ){ + this(); + defenseSkill = heroLevel + 5; //equal to base hero defense skill + } + + @Override + protected boolean act() { + int oldPos = pos; + boolean result = super.act(); + //partially simulates how the hero switches to idle animation + if ((pos == target || oldPos == pos) && sprite.looping()){ + sprite.idle(); + } + return result; + } + + @Override + public void defendPos(int cell) { + GLog.i(Messages.get(this, "direct_defend")); + super.defendPos(cell); + } + + @Override + public void followHero() { + GLog.i(Messages.get(this, "direct_follow")); + super.followHero(); + } + + @Override + public void targetChar(Char ch) { + GLog.i(Messages.get(this, "direct_attack")); + super.targetChar(ch); + } + + @Override + public int attackSkill(Char target) { + return defenseSkill+5; //equal to base hero attack skill + } + + @Override + public int damageRoll() { + return Random.NormalIntRange(5, 30); //+0 greatsword + } + + @Override + public int drRoll() { + return super.drRoll() + Random.NormalIntRange(1, 5); //+0 plate + } + + @Override + public float speed() { + float speed = super.speed(); + + //moves 2 tiles at a time when returning to the hero + if (state == WANDERING + && defendingPos == -1 + && Dungeon.level.distance(pos, Dungeon.hero.pos) > 1){ + speed *= 2; + } + + return speed; + } + + @Override + public CharSprite sprite() { + CharSprite sprite = super.sprite(); + ((LightAllySprite)sprite).setup(cls); + return sprite; + } + + private static final String HERO_CLS = "hero_cls"; + private static final String DEF_SKILL = "def_skill"; + + @Override + public void storeInBundle(Bundle bundle) { + super.storeInBundle(bundle); + bundle.put(HERO_CLS, cls); + bundle.put(DEF_SKILL, defenseSkill); + } + + @Override + public void restoreFromBundle(Bundle bundle) { + super.restoreFromBundle(bundle); + cls = bundle.getEnum(HERO_CLS, HeroClass.class); + defenseSkill = bundle.getInt(DEF_SKILL); + } + } + + public static class LightAllySprite extends MobSprite { + + public LightAllySprite() { + super(); + + setup(HeroClass.values()[Random.Int(5)]); + } + + public void setup(HeroClass cls){ + texture(cls.spritesheet()); + + TextureFilm film = new TextureFilm( HeroSprite.tiers(), 6, 12, 15 ); + + idle = new Animation( 1, true ); + idle.frames( film, 0, 0, 0, 1, 0, 0, 1, 1 ); + + run = new Animation( 20, true ); + run.frames( film, 2, 3, 4, 5, 6, 7 ); + + die = new Animation( 20, false ); + die.frames( film, 0 ); + + attack = new Animation( 15, false ); + attack.frames( film, 13, 14, 15, 0 ); + + play(idle, true); + resetColor(); + } + + @Override + public void link(Char ch) { + super.link(ch); + if (ch instanceof LightAlly){ + setup(((LightAlly) ch).cls); + } + } + + @Override + public void resetColor() { + super.resetColor(); + alpha(0.8f); + tint(1.33f, 1.33f, 0.8f, 0.6f); + rm = gm = bm = 0; + } + + @Override + public void die() { + super.die(); + emitter().start( ShaftParticle.FACTORY, 0.3f, 4 ); + emitter().start( Speck.factory( Speck.LIGHT ), 0.2f, 3 ); + } + + @Override + public void draw() { + if (alpha() >= 0.8f) alpha(0.8f); + rm = gm = bm = 0; //always flat and transparent + super.draw(); + } + } + } diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index c020a099a..cc106cc24 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -51,6 +51,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Feint; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.ShadowClone; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.ClericSpell; @@ -249,7 +250,15 @@ public abstract class Mob extends Char { return true; } - return state.act( enemyInFOV, justAlerted ); + boolean result = state.act( enemyInFOV, justAlerted ); + + //for updating hero FOV + if (buff(PowerOfMany.PowerBuff.class) != null){ + Dungeon.level.updateFieldOfView( this, fieldOfView ); + GameScene.updateFog(pos, viewDistance+(int)Math.ceil(speed())); + } + + return result; } //FIXME this is sort of a band-aid correction for allies needing more intelligent behaviour diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java index c71679248..e31360040 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/npcs/PrismaticImage.java @@ -247,7 +247,7 @@ public class PrismaticImage extends NPC { @Override public boolean act(boolean enemyInFOV, boolean justAlerted) { if (!enemyInFOV){ - Buff.affect(hero, PrismaticGuard.class).set( HP ); + Buff.affect(hero, PrismaticGuard.class).set( PrismaticImage.this ); destroy(); CellEmitter.get(pos).start( Speck.factory(Speck.LIGHT), 0.2f, 3 ); sprite.die(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java index c19088d30..4c52ad61c 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/items/wands/WandOfLivingEarth.java @@ -30,6 +30,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AllyBuff; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok; import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.NPC; @@ -110,6 +111,10 @@ public class WandOfLivingEarth extends DamageWand { guardian = new EarthGuardian(); guardian.setInfo(curUser, buffedLvl(), buff.armor); + if (buff.powerOfManyTurns > 0){ + Buff.affect(guardian, PowerOfMany.PowerBuff.class, buff.powerOfManyTurns); + } + //if the collision pos is occupied (likely will be), then spawn the guardian in the //adjacent cell which is closes to the user of the wand. if (ch != null){ @@ -255,7 +260,22 @@ public class WandOfLivingEarth extends DamageWand { private int wandLevel; private int armor; - private void addArmor( int wandLevel, int toAdd ){ + private float powerOfManyTurns = 0; + + @Override + public boolean act() { + if (powerOfManyTurns > 0){ + powerOfManyTurns--; + if (powerOfManyTurns <= 0){ + powerOfManyTurns = 0; + BuffIndicator.refreshHero(); + } + } + spend(TICK); + return true; + } + + private void addArmor(int wandLevel, int toAdd ){ this.wandLevel = Math.max(this.wandLevel, wandLevel); armor += toAdd; armor = Math.min(armor, 2*armorToGuardian()); @@ -276,6 +296,10 @@ public class WandOfLivingEarth extends DamageWand { } } + public boolean isEmpowered(){ + return powerOfManyTurns > 0; + } + @Override public int icon() { return BuffIndicator.ARMOR; @@ -283,7 +307,11 @@ public class WandOfLivingEarth extends DamageWand { @Override public void tintIcon(Image icon) { - icon.brightness(0.6f); + if (isEmpowered()){ + icon.hardlight(1.8f, 1.8f, 0.6f); + } else { + icon.brightness(0.6f); + } } @Override @@ -298,17 +326,24 @@ public class WandOfLivingEarth extends DamageWand { @Override public String desc() { - return Messages.get( this, "desc", armor, armorToGuardian()); + String desc = Messages.get( this, "desc", armor, armorToGuardian()); + if (isEmpowered()){ + desc += "\n\n" + Messages.get(this, "desc_many", (int)powerOfManyTurns); + } + return desc; } private static final String WAND_LEVEL = "wand_level"; private static final String ARMOR = "armor"; + private static final String POWER_TURNS = "power_turns"; + @Override public void storeInBundle(Bundle bundle) { super.storeInBundle(bundle); bundle.put(WAND_LEVEL, wandLevel); bundle.put(ARMOR, armor); + bundle.put(POWER_TURNS, powerOfManyTurns); } @Override @@ -316,6 +351,7 @@ public class WandOfLivingEarth extends DamageWand { super.restoreFromBundle(bundle); wandLevel = bundle.getInt(WAND_LEVEL); armor = bundle.getInt(ARMOR); + powerOfManyTurns = bundle.getFloat(POWER_TURNS); } } @@ -423,6 +459,9 @@ public class WandOfLivingEarth extends DamageWand { public boolean act(boolean enemyInFOV, boolean justAlerted) { if (!enemyInFOV){ Buff.affect(Dungeon.hero, RockArmor.class).addArmor(wandLevel, HP); + if (buff(PowerOfMany.PowerBuff.class) != null){ + Buff.affect(Dungeon.hero, RockArmor.class).powerOfManyTurns = buff(PowerOfMany.PowerBuff.class).cooldown()+1; + } Dungeon.hero.sprite.centerEmitter().burst(MagicMissile.EarthParticle.ATTRACT, 8 + wandLevel/2); destroy(); sprite.die(); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java index 9436854aa..19661f05f 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/journal/Bestiary.java @@ -22,6 +22,7 @@ package com.shatteredpixel.shatteredpixeldungeon.journal; import com.shatteredpixel.shatteredpixeldungeon.Badges; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.ShadowClone; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.rogue.SmokeBomb; @@ -235,7 +236,7 @@ public enum Bestiary { ALLY.addEntities(MirrorImage.class, PrismaticImage.class, DriedRose.GhostHero.class, WandOfWarding.Ward.class, WandOfWarding.Ward.WardSentry.class, WandOfLivingEarth.EarthGuardian.class, - ShadowClone.ShadowAlly.class, SmokeBomb.NinjaLog.class, SpiritHawk.HawkAlly.class); + ShadowClone.ShadowAlly.class, SmokeBomb.NinjaLog.class, SpiritHawk.HawkAlly.class, PowerOfMany.LightAlly.class); TRAP.addEntities(WornDartTrap.class, PoisonDartTrap.class, DisintegrationTrap.class, GatewayTrap.class, ChillingTrap.class, BurningTrap.class, ShockingTrap.class, AlarmTrap.class, GrippingTrap.class, TeleportationTrap.class, OozeTrap.class, diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java index ce3d84b4b..e910b3f31 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/levels/Level.java @@ -48,6 +48,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Shadows; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Talent; +import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.cleric.PowerOfMany; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.huntress.SpiritHawk; import com.shatteredpixel.shatteredpixeldungeon.actors.hero.spells.DivineSense; import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGeomancer; @@ -1415,7 +1416,8 @@ public abstract class Level implements Bundlable { for (Mob m : mobs){ if (m instanceof WandOfWarding.Ward || m instanceof WandOfRegrowth.Lotus - || m instanceof SpiritHawk.HawkAlly){ + || m instanceof SpiritHawk.HawkAlly + || m.buff(PowerOfMany.PowerBuff.class) != null){ if (m.fieldOfView == null || m.fieldOfView.length != length()){ m.fieldOfView = new boolean[length()]; Dungeon.level.updateFieldOfView( m, m.fieldOfView ); diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java index 646975644..27f3839ed 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/ui/BuffIndicator.java @@ -132,6 +132,7 @@ public class BuffIndicator extends Component { public static final int PROT_AURA = 80; public static final int ILLUMINATED = 81; public static final int TRINITY_FORM= 82; + public static final int MANY_POWER = 83; public static final int SIZE_SMALL = 7; public static final int SIZE_LARGE = 16;