v2.0.0: implement base challenge armor ability and all of its text
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.0 KiB |
@@ -457,6 +457,17 @@ actors.hero.abilities.huntress.spirithawk$hawkally.direct_attack=Your hawk moves
|
|||||||
actors.hero.abilities.huntress.spirithawk$hawkally.desc=A magical hawk, summoned by the Huntress. It glows a bright ethereal blue, its head constantly shifts around as it surveys the area.\n\nWhile it isn't much of a fighter its speed and vision make it excellent for scouting and distracting enemies.\n\nTurns remaining: %d.
|
actors.hero.abilities.huntress.spirithawk$hawkally.desc=A magical hawk, summoned by the Huntress. It glows a bright ethereal blue, its head constantly shifts around as it surveys the area.\n\nWhile it isn't much of a fighter its speed and vision make it excellent for scouting and distracting enemies.\n\nTurns remaining: %d.
|
||||||
actors.hero.abilities.huntress.spirithawk$hawkally.desc_dodges=Guaranteed dodges remaining: %d.
|
actors.hero.abilities.huntress.spirithawk$hawkally.desc_dodges=Guaranteed dodges remaining: %d.
|
||||||
|
|
||||||
|
actors.hero.abilities.duelist.challenge.name=challenge
|
||||||
|
actors.hero.abilities.duelist.challenge.prompt=Choose an enemy to challenge
|
||||||
|
actors.hero.abilities.duelist.challenge.already_dueling=You can only be in one duel at a time.
|
||||||
|
actors.hero.abilities.duelist.challenge.ally_target=You can only challenge enemies.
|
||||||
|
actors.hero.abilities.duelist.challenge.unreachable_target=You must be able to reach your target.
|
||||||
|
actors.hero.abilities.duelist.challenge.distant_target=That enemy is too far away to challenge.
|
||||||
|
actors.hero.abilities.duelist.challenge.short_desc=The Duelist _challenges_ a nearby enemy to a duel, temporarily freezing all other enemies.
|
||||||
|
actors.hero.abilities.duelist.challenge.desc=The Duelist challenges a nearby enemy to a duel. That enemy is compelled to fight her while all other enemies are temporarily frozen in time.\n\nThe target must be reachable and within 5 tiles of the Duelist. The duel lasts until 10 turns pass, the enemy dies, or the Duelist is more than 5 tiles away from the enemy.\n\nFrozen enemies are invulnerable. The Duelist's allies are not frozen by this ability, but if a boss is targeted its minions will not be frozen either.
|
||||||
|
actors.hero.abilities.duelist.challenge$duelparticipant.name=duel participant
|
||||||
|
actors.hero.abilities.duelist.challenge$duelparticipant.desc=This character is participating in a duel. They, and any of their allies or minions, are allowed to act normally while others are frozen.\n\nThe duel will last for a set amount of time, until one participant dies, or until the participants move more than 5 tiles away from eachother.\n\nTurns remaining: %d.
|
||||||
|
|
||||||
actors.hero.abilities.ratmogrify.name=ratmogrify
|
actors.hero.abilities.ratmogrify.name=ratmogrify
|
||||||
actors.hero.abilities.ratmogrify.cant_transform=You can't ratmogrify that!
|
actors.hero.abilities.ratmogrify.cant_transform=You can't ratmogrify that!
|
||||||
actors.hero.abilities.ratmogrify.too_strong=That enemy is too strong to ratmogrify!
|
actors.hero.abilities.ratmogrify.too_strong=That enemy is too strong to ratmogrify!
|
||||||
@@ -848,7 +859,20 @@ actors.hero.talent.secondary_charge.desc=_+1:_ The Champion's secondary weapon c
|
|||||||
actors.hero.talent.twin_upgrades.title=twin upgrades
|
actors.hero.talent.twin_upgrades.title=twin upgrades
|
||||||
actors.hero.talent.twin_upgrades.desc=_+1:_ If the weaker of the Champion's two equipped weapons is _2 or more tiers lower_ than the stronger one, it is boosted to the stronger weapon's level.\n\n_+2:_ If the weaker of the Champion's two equipped weapons is _1 or more tiers lower_ than the stronger one, it is boosted to the stronger weapon's level.\n\n_+3:_ If the weaker of the Champion's two equipped weapons is _the same tier or lower_ than the stronger one, it is boosted to the stronger weapon's level.
|
actors.hero.talent.twin_upgrades.desc=_+1:_ If the weaker of the Champion's two equipped weapons is _2 or more tiers lower_ than the stronger one, it is boosted to the stronger weapon's level.\n\n_+2:_ If the weaker of the Champion's two equipped weapons is _1 or more tiers lower_ than the stronger one, it is boosted to the stronger weapon's level.\n\n_+3:_ If the weaker of the Champion's two equipped weapons is _the same tier or lower_ than the stronger one, it is boosted to the stronger weapon's level.
|
||||||
actors.hero.talent.combined_lethality.title=combined lethality
|
actors.hero.talent.combined_lethality.title=combined lethality
|
||||||
actors.hero.talent.combined_lethality.desc=_+1:_ If the Champion uses two different weapon abilities successively, the second ability will execute any non-boss enemy _below 8% health_.\n\n_+2:_ If the Champion uses two different weapon abilities successively, the second ability will execute any non-boss enemy _below 17% health_.\n\n_+3:_ If the Champion uses two different weapon abilities successively, the second ability will execute any non-boss enemy _below 25% health_.\n\nIf the second ability does not contain an attack, this talent will instead trigger on the Champion's next attack within 5 turns.
|
actors.hero.talent.combined_lethality.desc=_+1:_ If the Champion uses two different weapon abilities successively, the second ability will execute any non-boss enemy _below 8% HP_.\n\n_+2:_ If the Champion uses two different weapon abilities successively, the second ability will execute any non-boss enemy _below 17% HP_.\n\n_+3:_ If the Champion uses two different weapon abilities successively, the second ability will execute any non-boss enemy _below 25% HP_.\n\nIf the second ability does not contain an attack, this talent will instead trigger on the Champion's next attack within 5 turns.
|
||||||
|
|
||||||
|
#second subclass
|
||||||
|
|
||||||
|
actors.hero.talent.close_the_gap.title=close the gap
|
||||||
|
actors.hero.talent.close_the_gap.desc=_+1:_ The Duelist blinks _up to two tiles_ toward her target when starting a duel.\n\n_+2:_ The Duelist blinks _up to three tiles_ toward her target when starting a duel.\n\n_+3:_ The Duelist blinks _up to four tiles_ toward her target when starting a duel.\n\n_+4:_ The Duelist blinks _up to five tiles_ toward her target when starting a duel.\n\nThis blink can go through enemies and hazards, and is taken into account when determining if an enemy is in range to be challenged.
|
||||||
|
actors.hero.talent.invigorating_victory.title=invigorating victory
|
||||||
|
actors.hero.talent.invigorating_victory.desc=_+1:_ If the Duelist defeats her target before the duel ends, she heals for _26% of the damage_ she took during the duel.\n\n_+2:_ If the Duelist defeats her target before the duel ends, she heals for _45% of the damage_ she took during the duel.\n\n_+3:_ If the Duelist defeats her target before the duel ends, she heals for _60% of the damage_ she took during the duel.\n\n_+4:_ If the Duelist defeats her target before the duel ends, she heals for _70% of the damage_ she took during the duel.
|
||||||
|
actors.hero.talent.elimination_match.title=elimination match
|
||||||
|
actors.hero.talent.elimination_match.desc=_+1:_ The Duelist can immediately challenge another enemy after a duel ends at a _20% reduced_ charge cost.\n\n_+2:_ The Duelist can immediately challenge another enemy after a duel ends at a _36% reduced_ charge cost.\n\n_+3:_ The Duelist can immediately challenge another enemy after a duel ends at a _50% reduced_ charge cost.\n\n_+4:_ The Duelist can immediately challenge another enemy after a duel ends at a _60% reduced_ charge cost.
|
||||||
|
|
||||||
|
#second armor ability
|
||||||
|
|
||||||
|
#third armor ability
|
||||||
|
|
||||||
#universal
|
#universal
|
||||||
actors.hero.talent.heroic_energy.title=heroic energy
|
actors.hero.talent.heroic_energy.title=heroic energy
|
||||||
|
|||||||
@@ -357,6 +357,15 @@ public abstract class Actor implements Bundlable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//'freezes' a character in time for a specified amount of time
|
||||||
|
//USE CAREFULLY! Manipulating time like this is useful for some gameplay effects but is tricky
|
||||||
|
public static void delayChar( Char ch, float time ){
|
||||||
|
ch.spendConstant(time);
|
||||||
|
for (Buff b : ch.buffs()){
|
||||||
|
b.spendConstant(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static synchronized Char findChar( int pos ) {
|
public static synchronized Char findChar( int pos ) {
|
||||||
for (Char ch : chars){
|
for (Char ch : chars){
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness;
|
|||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
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.duelist.Challenge;
|
||||||
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.hero.abilities.warrior.Endure;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Elemental;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Elemental;
|
||||||
@@ -842,6 +843,10 @@ public abstract class Char extends Actor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sprite != null && buff(Challenge.SpectatorFreeze.class) != null){
|
||||||
|
return; //can't add buffs while frozen and game is loaded
|
||||||
|
}
|
||||||
|
|
||||||
buffs.add( buff );
|
buffs.add( buff );
|
||||||
if (Actor.chars().contains(this)) Actor.add( buff );
|
if (Actor.chars().contains(this)) Actor.add( buff );
|
||||||
|
|
||||||
@@ -985,7 +990,7 @@ public abstract class Char extends Actor {
|
|||||||
//similar to isImmune, but only factors in damage.
|
//similar to isImmune, but only factors in damage.
|
||||||
//Is used in AI decision-making
|
//Is used in AI decision-making
|
||||||
public boolean isInvulnerable( Class effect ){
|
public boolean isInvulnerable( Class effect ){
|
||||||
return false;
|
return buff(Challenge.SpectatorFreeze.class) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HashSet<Property> properties = new HashSet<>();
|
protected HashSet<Property> properties = new HashSet<>();
|
||||||
@@ -1004,6 +1009,7 @@ public abstract class Char extends Actor {
|
|||||||
new HashSet<Class>( Arrays.asList(AllyBuff.class, Dread.class) )),
|
new HashSet<Class>( Arrays.asList(AllyBuff.class, Dread.class) )),
|
||||||
MINIBOSS ( new HashSet<Class>(),
|
MINIBOSS ( new HashSet<Class>(),
|
||||||
new HashSet<Class>( Arrays.asList(AllyBuff.class, Dread.class) )),
|
new HashSet<Class>( Arrays.asList(AllyBuff.class, Dread.class) )),
|
||||||
|
BOSS_MINION,
|
||||||
UNDEAD,
|
UNDEAD,
|
||||||
DEMONIC,
|
DEMONIC,
|
||||||
INORGANIC ( new HashSet<Class>(),
|
INORGANIC ( new HashSet<Class>(),
|
||||||
|
|||||||
@@ -2052,7 +2052,7 @@ public class Hero extends Char {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInvulnerable(Class effect) {
|
public boolean isInvulnerable(Class effect) {
|
||||||
return buff(AnkhInvulnerability.class) != null;
|
return super.isInvulnerable(effect) || buff(AnkhInvulnerability.class) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean search( boolean intentional ) {
|
public boolean search( boolean intentional ) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import com.shatteredpixel.shatteredpixeldungeon.QuickSlot;
|
|||||||
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.ArmorAbility;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Challenge;
|
||||||
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.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;
|
||||||
@@ -254,7 +255,7 @@ public enum HeroClass {
|
|||||||
case HUNTRESS:
|
case HUNTRESS:
|
||||||
return new ArmorAbility[]{new SpectralBlades(), new NaturesPower(), new SpiritHawk()};
|
return new ArmorAbility[]{new SpectralBlades(), new NaturesPower(), new SpiritHawk()};
|
||||||
case DUELIST:
|
case DUELIST:
|
||||||
return new ArmorAbility[]{};
|
return new ArmorAbility[]{new Challenge()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ public enum Talent {
|
|||||||
//Duelist S2 T3
|
//Duelist S2 T3
|
||||||
DUELIST_S2_1(142, 3), DUELIST_S2_2(143, 3), DUELIST_S2_3(144, 3),
|
DUELIST_S2_1(142, 3), DUELIST_S2_2(143, 3), DUELIST_S2_3(144, 3),
|
||||||
//Duelist A1 T4
|
//Duelist A1 T4
|
||||||
DUELIST_A1_1(145, 4), DUELIST_A1_2(146, 4), DUELIST_A1_3(147, 4),
|
CLOSE_THE_GAP(145, 4), INVIGORATING_VICTORY(146, 4), ELIMINATION_MATCH(147, 4),
|
||||||
//Duelist A2 T4
|
//Duelist A2 T4
|
||||||
DUELIST_A2_1(148, 4), DUELIST_A2_2(149, 4), DUELIST_A2_3(150, 4),
|
DUELIST_A2_1(148, 4), DUELIST_A2_2(149, 4), DUELIST_A2_3(150, 4),
|
||||||
//Duelist A3 T4
|
//Duelist A3 T4
|
||||||
|
|||||||
@@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2023 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.abilities.duelist;
|
||||||
|
|
||||||
|
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.BlobImmunity;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Doom;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.FlavourBuff;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||||
|
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.items.armor.ClassArmor;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ui.HeroIcon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||||
|
import com.watabou.noosa.audio.Sample;
|
||||||
|
import com.watabou.utils.Bundle;
|
||||||
|
import com.watabou.utils.PathFinder;
|
||||||
|
|
||||||
|
public class Challenge extends ArmorAbility {
|
||||||
|
|
||||||
|
{
|
||||||
|
baseChargeUse = 35;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int icon() {
|
||||||
|
return HeroIcon.CHALLENGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String targetingPrompt() {
|
||||||
|
return Messages.get(this, "prompt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int targetedPos(Char user, int dst) {
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void activate(ClassArmor armor, Hero hero, Integer target) {
|
||||||
|
if (target == null || !Dungeon.level.heroFOV[target]){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Char targetCh = Actor.findChar(target);
|
||||||
|
|
||||||
|
if (hero.buff(DuelParticipant.class) != null){
|
||||||
|
GLog.w(Messages.get(this, "already_dueling"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetCh != null){
|
||||||
|
|
||||||
|
if (targetCh.alignment == hero.alignment){
|
||||||
|
GLog.w(Messages.get(this, "ally_target"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean[] passable = Dungeon.level.passable.clone();
|
||||||
|
for (Char c : Actor.chars()) {
|
||||||
|
if (c != hero) passable[c.pos] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PathFinder.buildDistanceMap(targetCh.pos, passable);
|
||||||
|
if (PathFinder.distance[hero.pos] == Integer.MAX_VALUE){
|
||||||
|
GLog.w(Messages.get(this, "unreachable_target"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Dungeon.level.distance(hero.pos, targetCh.pos) >= 5){
|
||||||
|
GLog.w(Messages.get(this, "distant_target"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean bossTarget = Char.hasProp(targetCh, Char.Property.BOSS);
|
||||||
|
for (Char toFreeze : Actor.chars()){
|
||||||
|
if (toFreeze != targetCh && toFreeze.alignment != hero.alignment
|
||||||
|
&& (!bossTarget || !(Char.hasProp(targetCh, Char.Property.BOSS) || Char.hasProp(targetCh, Char.Property.BOSS_MINION)))) {
|
||||||
|
Actor.delayChar(toFreeze, DuelParticipant.DURATION);
|
||||||
|
Buff.affect(toFreeze, SpectatorFreeze.class, DuelParticipant.DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Buff.affect(targetCh, DuelParticipant.class);
|
||||||
|
Buff.affect(hero, DuelParticipant.class);
|
||||||
|
if (targetCh instanceof Mob){
|
||||||
|
((Mob) targetCh).aggro(hero);
|
||||||
|
}
|
||||||
|
|
||||||
|
GameScene.flash(0x80FFFFFF);
|
||||||
|
Sample.INSTANCE.play(Assets.Sounds.DESCEND);
|
||||||
|
|
||||||
|
armor.charge -= chargeUse( hero );
|
||||||
|
armor.updateQuickslot();
|
||||||
|
hero.sprite.zap(target);
|
||||||
|
|
||||||
|
hero.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Talent[] talents() {
|
||||||
|
return new Talent[]{Talent.CLOSE_THE_GAP, Talent.INVIGORATING_VICTORY, Talent.ELIMINATION_MATCH, Talent.HEROIC_ENERGY};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DuelParticipant extends Buff {
|
||||||
|
|
||||||
|
public static float DURATION = 10f;
|
||||||
|
|
||||||
|
private int left = (int)DURATION;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int icon() {
|
||||||
|
return BuffIndicator.CHALLENGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float iconFadePercent() {
|
||||||
|
return Math.max(0, (DURATION - left) / DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String iconTextDisplay() {
|
||||||
|
return Integer.toString(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean act() {
|
||||||
|
|
||||||
|
left--;
|
||||||
|
if (left == 0) {
|
||||||
|
detach();
|
||||||
|
} else {
|
||||||
|
Char other = null;
|
||||||
|
for (Char ch : Actor.chars()){
|
||||||
|
if (ch != target && ch.buff(DuelParticipant.class) != null){
|
||||||
|
other = ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (other == null){
|
||||||
|
detach();
|
||||||
|
} else if (Dungeon.level.distance(target.pos, other.pos) > 5){
|
||||||
|
detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spend(TICK);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void detach() {
|
||||||
|
super.detach();
|
||||||
|
if (!target.isAlive()) {
|
||||||
|
if (target.alignment != Dungeon.hero.alignment){
|
||||||
|
Sample.INSTANCE.play(Assets.Sounds.BOSS);
|
||||||
|
GameScene.flash(0x80FFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Char ch : Actor.chars()) {
|
||||||
|
if (ch.buff(SpectatorFreeze.class) != null) {
|
||||||
|
ch.buff(SpectatorFreeze.class).detach();
|
||||||
|
}
|
||||||
|
if (ch.buff(DuelParticipant.class) != null && ch != target) {
|
||||||
|
ch.buff(DuelParticipant.class).detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (target == Dungeon.hero){
|
||||||
|
GameScene.flash(0x80FFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String desc() {
|
||||||
|
return Messages.get(this, "desc", left);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String LEFT = "left";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeInBundle(Bundle bundle) {
|
||||||
|
super.storeInBundle(bundle);
|
||||||
|
bundle.put(LEFT, left);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreFromBundle(Bundle bundle) {
|
||||||
|
super.restoreFromBundle(bundle);
|
||||||
|
left = bundle.getInt(LEFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SpectatorFreeze extends FlavourBuff {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fx(boolean on) {
|
||||||
|
if (on) {
|
||||||
|
target.sprite.add(CharSprite.State.DARKENED);
|
||||||
|
target.sprite.add(CharSprite.State.PARALYSED);
|
||||||
|
} else {
|
||||||
|
//allies can't be spectator frozen, so just check doom
|
||||||
|
if (target.buff(Doom.class) == null) target.sprite.remove(CharSprite.State.DARKENED);
|
||||||
|
if (target.paralysed == 0) target.sprite.remove(CharSprite.State.PARALYSED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void detach(){
|
||||||
|
super.detach();
|
||||||
|
if (cooldown() > 0) {
|
||||||
|
Actor.delayChar(target, -cooldown());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
immunities.addAll(new BlobImmunity().immunities());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -503,7 +503,7 @@ public class DM300 extends Mob {
|
|||||||
invulnWarned = true;
|
invulnWarned = true;
|
||||||
GLog.w(Messages.get(this, "charging_hint"));
|
GLog.w(Messages.get(this, "charging_hint"));
|
||||||
}
|
}
|
||||||
return supercharged;
|
return supercharged || super.isInvulnerable(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void supercharge(){
|
public void supercharge(){
|
||||||
|
|||||||
@@ -438,7 +438,11 @@ public class DwarfKing extends Mob {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInvulnerable(Class effect) {
|
public boolean isInvulnerable(Class effect) {
|
||||||
return phase == 2 && effect != KingDamager.class;
|
if (effect == KingDamager.class){
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return phase == 2 || super.isInvulnerable(effect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -562,6 +566,7 @@ public class DwarfKing extends Mob {
|
|||||||
|
|
||||||
public static class DKGhoul extends Ghoul {
|
public static class DKGhoul extends Ghoul {
|
||||||
{
|
{
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
state = HUNTING;
|
state = HUNTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,12 +579,14 @@ public class DwarfKing extends Mob {
|
|||||||
|
|
||||||
public static class DKMonk extends Monk {
|
public static class DKMonk extends Monk {
|
||||||
{
|
{
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
state = HUNTING;
|
state = HUNTING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class DKWarlock extends Warlock {
|
public static class DKWarlock extends Warlock {
|
||||||
{
|
{
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
state = HUNTING;
|
state = HUNTING;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,6 +601,7 @@ public class DwarfKing extends Mob {
|
|||||||
|
|
||||||
public static class DKGolem extends Golem {
|
public static class DKGolem extends Golem {
|
||||||
{
|
{
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
state = HUNTING;
|
state = HUNTING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.SacrificialFire;
|
|||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AllyBuff;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.AllyBuff;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ChampionEnemy;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.ChampionEnemy;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.abilities.duelist.Challenge;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
|
import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
|
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
|
||||||
@@ -261,7 +262,10 @@ public class Ghoul extends Mob {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
turnsToRevive--;
|
//have to delay this manually here are a downed ghouls can't be directly frozen otherwise
|
||||||
|
if (target.buff(Challenge.DuelParticipant.class) == null) {
|
||||||
|
turnsToRevive--;
|
||||||
|
}
|
||||||
if (turnsToRevive <= 0){
|
if (turnsToRevive <= 0){
|
||||||
if (Actor.findChar( ghoul.pos ) != null) {
|
if (Actor.findChar( ghoul.pos ) != null) {
|
||||||
ArrayList<Integer> candidates = new ArrayList<>();
|
ArrayList<Integer> candidates = new ArrayList<>();
|
||||||
@@ -345,7 +349,10 @@ public class Ghoul extends Mob {
|
|||||||
public static Ghoul searchForHost(Ghoul dieing){
|
public static Ghoul searchForHost(Ghoul dieing){
|
||||||
|
|
||||||
for (Char ch : Actor.chars()){
|
for (Char ch : Actor.chars()){
|
||||||
if (ch != dieing && ch instanceof Ghoul && ch.alignment == dieing.alignment){
|
//don't count hero ally ghouls or duel frozen ghouls
|
||||||
|
if (ch != dieing && ch instanceof Ghoul
|
||||||
|
&& ch.alignment == dieing.alignment
|
||||||
|
&& ch.buff(Challenge.SpectatorFreeze.class) == null){
|
||||||
if (ch.fieldOfView == null){
|
if (ch.fieldOfView == null){
|
||||||
ch.fieldOfView = new boolean[Dungeon.level.length()];
|
ch.fieldOfView = new boolean[Dungeon.level.length()];
|
||||||
Dungeon.level.updateFieldOfView( ch, ch.fieldOfView );
|
Dungeon.level.updateFieldOfView( ch, ch.fieldOfView );
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ public class Pylon extends Mob {
|
|||||||
maxLvl = -2;
|
maxLvl = -2;
|
||||||
|
|
||||||
properties.add(Property.MINIBOSS);
|
properties.add(Property.MINIBOSS);
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
properties.add(Property.INORGANIC);
|
properties.add(Property.INORGANIC);
|
||||||
properties.add(Property.ELECTRIC);
|
properties.add(Property.ELECTRIC);
|
||||||
properties.add(Property.IMMOVABLE);
|
properties.add(Property.IMMOVABLE);
|
||||||
@@ -178,7 +179,7 @@ public class Pylon extends Mob {
|
|||||||
@Override
|
@Override
|
||||||
public boolean isInvulnerable(Class effect) {
|
public boolean isInvulnerable(Class effect) {
|
||||||
//immune to damage when inactive
|
//immune to damage when inactive
|
||||||
return (alignment == Alignment.NEUTRAL);
|
return alignment == Alignment.NEUTRAL || super.isInvulnerable(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -368,7 +368,7 @@ public class YogDzewa extends Mob {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isInvulnerable(Class effect) {
|
public boolean isInvulnerable(Class effect) {
|
||||||
return phase == 0 || findFist() != null;
|
return phase == 0 || findFist() != null || super.isInvulnerable(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -629,6 +629,7 @@ public class YogDzewa extends Mob {
|
|||||||
maxLvl = -2;
|
maxLvl = -2;
|
||||||
|
|
||||||
properties.add(Property.DEMONIC);
|
properties.add(Property.DEMONIC);
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -649,15 +650,22 @@ public class YogDzewa extends Mob {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//used so death to yog's ripper demons have their own rankings description
|
//used so death to yog's ripper demons have their own rankings description
|
||||||
public static class YogRipper extends RipperDemon {}
|
public static class YogRipper extends RipperDemon {
|
||||||
|
{
|
||||||
|
maxLvl = -2;
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
|
}
|
||||||
|
}
|
||||||
public static class YogEye extends Eye {
|
public static class YogEye extends Eye {
|
||||||
{
|
{
|
||||||
maxLvl = -2;
|
maxLvl = -2;
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static class YogScorpio extends Scorpio {
|
public static class YogScorpio extends Scorpio {
|
||||||
{
|
{
|
||||||
maxLvl = -2;
|
maxLvl = -2;
|
||||||
|
properties.add(Property.BOSS_MINION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ public abstract class YogFist extends Mob {
|
|||||||
invulnWarned = true;
|
invulnWarned = true;
|
||||||
GLog.w(Messages.get(this, "invuln_warn"));
|
GLog.w(Messages.get(this, "invuln_warn"));
|
||||||
}
|
}
|
||||||
return isNearYog();
|
return isNearYog() || super.isInvulnerable(effect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public class BuffIndicator extends Component {
|
|||||||
public static final int DUEL_DANCE = 64;
|
public static final int DUEL_DANCE = 64;
|
||||||
public static final int DUEL_BRAWL = 65;
|
public static final int DUEL_BRAWL = 65;
|
||||||
public static final int DUEL_XBOW = 66;
|
public static final int DUEL_XBOW = 66;
|
||||||
|
public static final int CHALLENGE = 67;
|
||||||
|
|
||||||
public static final int SIZE_SMALL = 7;
|
public static final int SIZE_SMALL = 7;
|
||||||
public static final int SIZE_LARGE = 16;
|
public static final int SIZE_LARGE = 16;
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ public class HeroIcon extends Image {
|
|||||||
public static final int SPECTRAL_BLADES = 25;
|
public static final int SPECTRAL_BLADES = 25;
|
||||||
public static final int NATURES_POWER = 26;
|
public static final int NATURES_POWER = 26;
|
||||||
public static final int SPIRIT_HAWK = 27;
|
public static final int SPIRIT_HAWK = 27;
|
||||||
public static final int RATMOGRIFY = 28;
|
public static final int CHALLENGE = 28;
|
||||||
|
public static final int DUELIST_2 = 29;
|
||||||
|
public static final int DUELIST_3 = 30;
|
||||||
|
public static final int RATMOGRIFY = 33;
|
||||||
|
|
||||||
public HeroIcon(HeroSubClass subCls){
|
public HeroIcon(HeroSubClass subCls){
|
||||||
super( Assets.Interfaces.HERO_ICONS );
|
super( Assets.Interfaces.HERO_ICONS );
|
||||||
|
|||||||