v0.8.0: Fully implemented the new Yog-Dzewa fight!
This commit is contained in:
parent
60453b2a4e
commit
b697ad1cae
|
@ -22,31 +22,32 @@
|
|||
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Charm;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Cripple;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Vertigo;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.TargetedCell;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PurpleParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfRetribution;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.exotic.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Grim;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.GrimTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.FistSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.LarvaSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.YogSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Bundle;
|
||||
|
@ -55,14 +56,15 @@ import com.watabou.utils.Random;
|
|||
import com.watabou.utils.Reflection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class YogDzewa extends Mob {
|
||||
|
||||
{
|
||||
spriteClass = YogSprite.class;
|
||||
|
||||
HP = HT = 600;
|
||||
HP = HT = 1000;
|
||||
|
||||
EXP = 50;
|
||||
|
||||
|
@ -74,25 +76,212 @@ public class YogDzewa extends Mob {
|
|||
}
|
||||
|
||||
private int phase = 0;
|
||||
private Class[] toSummon = new Class[3];
|
||||
|
||||
private float abilityCooldown;
|
||||
private static final int MIN_ABILITY_CD = 10;
|
||||
private static final int MAX_ABILITY_CD = 15;
|
||||
|
||||
private float summonCooldown;
|
||||
private static final int MIN_SUMMON_CD = 10;
|
||||
private static final int MAX_SUMMON_CD = 15;
|
||||
|
||||
private ArrayList<Class> fistSummons = new ArrayList<>();
|
||||
{
|
||||
toSummon[0] = (Random.Int(2) == 0 ? YogFist.Burning.class : YogFist.Soiled.class);
|
||||
toSummon[1] = (Random.Int(2) == 0 ? YogFist.Rotting.class : YogFist.Rusted.class);
|
||||
toSummon[2] = (Random.Int(2) == 0 ? YogFist.Bright.class : YogFist.Dark.class);
|
||||
Random.shuffle(toSummon);
|
||||
fistSummons.add(Random.Int(2) == 0 ? YogFist.Burning.class : YogFist.Soiled.class);
|
||||
fistSummons.add(Random.Int(2) == 0 ? YogFist.Rotting.class : YogFist.Rusted.class);
|
||||
fistSummons.add(Random.Int(2) == 0 ? YogFist.Bright.class : YogFist.Dark.class);
|
||||
Random.shuffle(fistSummons);
|
||||
}
|
||||
|
||||
private static final int SUMMON_DECK_SIZE = 4;
|
||||
private ArrayList<Class> regularSummons = new ArrayList<>();
|
||||
{
|
||||
for (int i = 0; i < SUMMON_DECK_SIZE; i++){
|
||||
if (i >= Statistics.spawnersAlive){
|
||||
regularSummons.add(Larva.class);
|
||||
} else {
|
||||
regularSummons.add(YogRipper.class);
|
||||
}
|
||||
}
|
||||
Random.shuffle(regularSummons);
|
||||
}
|
||||
|
||||
private ArrayList<Integer> targetedCells = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
if (phase == 0 && Dungeon.hero.viewDistance >= Dungeon.level.distance(pos, Dungeon.hero.pos)){
|
||||
Dungeon.observe();
|
||||
if (Dungeon.level.heroFOV[pos]) {
|
||||
notice();
|
||||
}
|
||||
}
|
||||
|
||||
if (phase == 4 && findFist() == null){
|
||||
yell(Messages.get(this, "hope"));
|
||||
summonCooldown = -15; //summon a burst of minions!
|
||||
phase = 5;
|
||||
}
|
||||
|
||||
if (phase == 0){
|
||||
spend(TICK);
|
||||
return true;
|
||||
} else {
|
||||
|
||||
boolean terrainAffected = false;
|
||||
HashSet<Char> affected = new HashSet<>();
|
||||
for (int i : targetedCells){
|
||||
Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP);
|
||||
//shoot beams
|
||||
sprite.parent.add(new Beam.DeathRay(sprite.center(), DungeonTilemap.raisedTileCenterToWorld(b.collisionPos)));
|
||||
for (int p : b.path){
|
||||
Char ch = Actor.findChar(p);
|
||||
if (ch != null && ch.alignment != alignment){
|
||||
affected.add(ch);
|
||||
}
|
||||
if (Dungeon.level.flamable[p]){
|
||||
Dungeon.level.destroy( p );
|
||||
GameScene.updateMap( p );
|
||||
terrainAffected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (terrainAffected){
|
||||
Dungeon.observe();
|
||||
}
|
||||
for (Char ch : affected){
|
||||
ch.damage(Random.NormalIntRange(20, 40), new Eye.DeathGaze());
|
||||
|
||||
if (Dungeon.level.heroFOV[pos]) {
|
||||
ch.sprite.flash();
|
||||
CellEmitter.center( pos ).burst( PurpleParticle.BURST, Random.IntRange( 1, 2 ) );
|
||||
}
|
||||
if (!ch.isAlive() && ch == Dungeon.hero) {
|
||||
Dungeon.fail( getClass() );
|
||||
GLog.n( Messages.get(Char.class, "kill", name()) );
|
||||
}
|
||||
}
|
||||
targetedCells.clear();
|
||||
|
||||
if (abilityCooldown <= 0){
|
||||
|
||||
int beams = 1 + (HT - HP)/400;
|
||||
HashSet<Integer> affectedCells = new HashSet<>();
|
||||
for (int i = 0; i < beams; i++){
|
||||
|
||||
int targetPos = Dungeon.hero.pos;
|
||||
if (i != 0){
|
||||
do {
|
||||
targetPos = Dungeon.hero.pos + PathFinder.NEIGHBOURS8[Random.Int(8)];
|
||||
} while (Dungeon.level.trueDistance(pos, Dungeon.hero.pos)
|
||||
> Dungeon.level.trueDistance(pos, targetPos));
|
||||
}
|
||||
targetedCells.add(targetPos);
|
||||
Ballistica b = new Ballistica(pos, targetPos, Ballistica.WONT_STOP);
|
||||
affectedCells.addAll(b.path);
|
||||
}
|
||||
|
||||
//remove one beam if multiple shots would cause every cell next to the hero to be targeted
|
||||
boolean allAdjTargeted = true;
|
||||
for (int i : PathFinder.NEIGHBOURS9){
|
||||
if (!affectedCells.contains(Dungeon.hero.pos + i) && Dungeon.level.passable[Dungeon.hero.pos + i]){
|
||||
allAdjTargeted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allAdjTargeted){
|
||||
targetedCells.remove(targetedCells.size()-1);
|
||||
}
|
||||
for (int i : targetedCells){
|
||||
Ballistica b = new Ballistica(pos, i, Ballistica.WONT_STOP);
|
||||
for (int p : b.path){
|
||||
sprite.parent.add(new TargetedCell(p, 0xFF0000));
|
||||
affectedCells.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
//wait extra time to let a crippled/rooted hero evade
|
||||
if (Dungeon.hero.buff(Cripple.class) != null){
|
||||
spend(TICK);
|
||||
} else if (Dungeon.hero.buff(Roots.class) != null){
|
||||
spend(Dungeon.hero.buff(Roots.class).cooldown());
|
||||
}
|
||||
|
||||
Dungeon.hero.interrupt();
|
||||
|
||||
abilityCooldown += Random.NormalFloat(MIN_ABILITY_CD, MAX_ABILITY_CD);
|
||||
abilityCooldown -= phase;
|
||||
|
||||
}
|
||||
|
||||
while (summonCooldown <= 0){
|
||||
|
||||
Class<?extends Mob> cls = regularSummons.remove(0);
|
||||
Mob summon = Reflection.newInstance(cls);
|
||||
regularSummons.add(cls);
|
||||
|
||||
int spawnPos = -1;
|
||||
for (int i : PathFinder.NEIGHBOURS8){
|
||||
if (Actor.findChar(pos+i) == null){
|
||||
if (spawnPos == -1 || Dungeon.level.trueDistance(Dungeon.hero.pos, spawnPos) > Dungeon.level.trueDistance(Dungeon.hero.pos, pos+i)){
|
||||
spawnPos = pos + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spawnPos != -1) {
|
||||
summon.pos = spawnPos;
|
||||
GameScene.add( summon );
|
||||
Actor.addDelayed( new Pushing( summon, pos, summon.pos ), -1 );
|
||||
|
||||
summonCooldown += Random.NormalFloat(MIN_SUMMON_CD, MAX_SUMMON_CD);
|
||||
summonCooldown -= phase;
|
||||
if (findFist() != null){
|
||||
summonCooldown += MIN_SUMMON_CD - phase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (summonCooldown > 0) summonCooldown--;
|
||||
if (abilityCooldown > 0) abilityCooldown--;
|
||||
|
||||
//extra fast abilities and summons at the final 100 HP
|
||||
if (phase == 5 && abilityCooldown > 2){
|
||||
abilityCooldown = 2;
|
||||
}
|
||||
if (phase == 5 && summonCooldown > 3){
|
||||
summonCooldown = 3;
|
||||
}
|
||||
|
||||
spend(TICK);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return super.isAlive() || phase != 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
|
||||
if (findFist() != null){
|
||||
if (phase == 0 || findFist() != null){
|
||||
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
|
||||
return;
|
||||
}
|
||||
|
||||
int preHP = HP;
|
||||
super.damage( dmg, src );
|
||||
int dmgTaken = preHP - HP;
|
||||
|
||||
abilityCooldown -= dmgTaken/10f;
|
||||
summonCooldown -= dmgTaken/10f;
|
||||
|
||||
if (phase < 4 && HP <= HT - 300*phase){
|
||||
HP = HT - 300*phase;
|
||||
|
||||
if (phase < 3 && HP <= HT * (3 - phase)/4f){
|
||||
Dungeon.level.viewDistance--;
|
||||
if (Dungeon.hero.buff(Light.class) == null){
|
||||
Dungeon.hero.viewDistance = Dungeon.level.viewDistance;
|
||||
|
@ -101,14 +290,16 @@ public class YogDzewa extends Mob {
|
|||
GLog.n(Messages.get(this, "darkness"));
|
||||
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
|
||||
|
||||
YogFist fist = (YogFist) Reflection.newInstance(toSummon[phase]);
|
||||
YogFist fist = (YogFist) Reflection.newInstance(fistSummons.remove(0));
|
||||
fist.pos = Dungeon.level.exit;
|
||||
|
||||
//TODO change based on what fist is summoned?
|
||||
CellEmitter.get(Dungeon.level.exit-1).burst(ShadowParticle.UP, 25);
|
||||
CellEmitter.get(Dungeon.level.exit).burst(ShadowParticle.UP, 100);
|
||||
CellEmitter.get(Dungeon.level.exit+1).burst(ShadowParticle.UP, 25);
|
||||
|
||||
if (abilityCooldown < 5) abilityCooldown = 5;
|
||||
if (summonCooldown < 5) summonCooldown = 5;
|
||||
|
||||
int targetPos = Dungeon.level.exit + Dungeon.level.width();
|
||||
if (Actor.findChar(targetPos) == null){
|
||||
fist.pos = targetPos;
|
||||
|
@ -118,7 +309,7 @@ public class YogDzewa extends Mob {
|
|||
fist.pos = targetPos+1;
|
||||
}
|
||||
|
||||
GameScene.add(fist, 1);
|
||||
GameScene.add(fist, 3);
|
||||
Actor.addDelayed( new Pushing( fist, Dungeon.level.exit, fist.pos ), -1 );
|
||||
phase++;
|
||||
}
|
||||
|
@ -165,7 +356,6 @@ public class YogDzewa extends Mob {
|
|||
|
||||
@Override
|
||||
public void notice() {
|
||||
super.notice();
|
||||
if (!BossHealthBar.isAssigned()) {
|
||||
BossHealthBar.assignBoss(this);
|
||||
yell(Messages.get(this, "notice"));
|
||||
|
@ -175,27 +365,78 @@ public class YogDzewa extends Mob {
|
|||
((DriedRose.GhostHero) ch).sayBoss();
|
||||
}
|
||||
}
|
||||
if (phase == 0) {
|
||||
phase = 1;
|
||||
summonCooldown = Random.NormalFloat(MIN_SUMMON_CD, MAX_SUMMON_CD);
|
||||
abilityCooldown = Random.NormalFloat(MIN_ABILITY_CD, MAX_ABILITY_CD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
String desc = super.description();
|
||||
|
||||
if (Statistics.spawnersAlive > 0){
|
||||
desc += "\n\n" + Messages.get(this, "desc_spawners");
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
{
|
||||
immunities.add( Grim.class );
|
||||
immunities.add( GrimTrap.class );
|
||||
immunities.add( Terror.class );
|
||||
immunities.add( Amok.class );
|
||||
immunities.add( Charm.class );
|
||||
immunities.add( Sleep.class );
|
||||
immunities.add( Burning.class );
|
||||
immunities.add( ToxicGas.class );
|
||||
immunities.add( ScrollOfRetribution.class );
|
||||
immunities.add( ScrollOfPsionicBlast.class );
|
||||
immunities.add( Vertigo.class );
|
||||
}
|
||||
|
||||
private static final String PHASE = "phase";
|
||||
|
||||
private static final String ABILITY_CD = "ability_cd";
|
||||
private static final String SUMMON_CD = "summon_cd";
|
||||
|
||||
private static final String FIST_SUMMONS = "fist_summons";
|
||||
private static final String REGULAR_SUMMONS = "regular_summons";
|
||||
|
||||
private static final String TARGETED_CELLS = "targeted_cells";
|
||||
|
||||
@Override
|
||||
public void storeInBundle(Bundle bundle) {
|
||||
super.storeInBundle(bundle);
|
||||
bundle.put(PHASE, phase);
|
||||
|
||||
bundle.put(ABILITY_CD, abilityCooldown);
|
||||
bundle.put(SUMMON_CD, summonCooldown);
|
||||
|
||||
bundle.put(FIST_SUMMONS, fistSummons.toArray(new Class[0]));
|
||||
bundle.put(REGULAR_SUMMONS, regularSummons.toArray(new Class[0]));
|
||||
|
||||
int[] bundleArr = new int[targetedCells.size()];
|
||||
for (int i = 0; i < targetedCells.size(); i++){
|
||||
bundleArr[i] = targetedCells.get(i);
|
||||
}
|
||||
bundle.put(TARGETED_CELLS, bundleArr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
BossHealthBar.assignBoss(this);
|
||||
phase = bundle.getInt(PHASE);
|
||||
if (phase != 0) BossHealthBar.assignBoss(this);
|
||||
|
||||
abilityCooldown = bundle.getFloat(ABILITY_CD);
|
||||
summonCooldown = bundle.getFloat(SUMMON_CD);
|
||||
|
||||
fistSummons.clear();
|
||||
Collections.addAll(fistSummons, bundle.getClassArray(FIST_SUMMONS));
|
||||
regularSummons.clear();
|
||||
Collections.addAll(regularSummons, bundle.getClassArray(REGULAR_SUMMONS));
|
||||
|
||||
for (int i : bundle.getIntArray(TARGETED_CELLS)){
|
||||
targetedCells.add(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Larva extends Mob {
|
||||
|
@ -203,8 +444,9 @@ public class YogDzewa extends Mob {
|
|||
{
|
||||
spriteClass = LarvaSprite.class;
|
||||
|
||||
HP = HT = 25;
|
||||
defenseSkill = 20;
|
||||
HP = HT = 20;
|
||||
defenseSkill = 12;
|
||||
viewDistance = Light.DISTANCE;
|
||||
|
||||
EXP = 5;
|
||||
maxLvl = -2;
|
||||
|
@ -221,13 +463,20 @@ public class YogDzewa extends Mob {
|
|||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 22, 30 );
|
||||
return Random.NormalIntRange( 15, 25 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drRoll() {
|
||||
return Random.NormalIntRange(0, 8);
|
||||
return Random.NormalIntRange(0, 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//used so death to yog's ripper demons have their own rankings description and are more aggro
|
||||
public static class YogRipper extends RipperDemon {
|
||||
{
|
||||
state = HUNTING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bleeding;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Cripple;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Ooze;
|
||||
|
@ -48,6 +47,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.FistSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
|
@ -55,13 +55,15 @@ public abstract class YogFist extends Mob {
|
|||
|
||||
{
|
||||
HP = HT = 300;
|
||||
defenseSkill = 25;
|
||||
defenseSkill = 20;
|
||||
|
||||
viewDistance = Light.DISTANCE;
|
||||
|
||||
//for doomed resistance
|
||||
EXP = 25;
|
||||
maxLvl = -2;
|
||||
|
||||
state = WANDERING;
|
||||
state = HUNTING;
|
||||
|
||||
properties.add(Property.MINIBOSS);
|
||||
properties.add(Property.DEMONIC);
|
||||
|
@ -71,7 +73,7 @@ public abstract class YogFist extends Mob {
|
|||
protected boolean canRangedInMelee = true;
|
||||
|
||||
protected void incrementRangedCooldown(){
|
||||
rangedCooldown += Random.NormalFloat(6, 9);
|
||||
rangedCooldown += Random.NormalFloat(8, 12);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,6 +91,26 @@ public abstract class YogFist extends Mob {
|
|||
}
|
||||
}
|
||||
|
||||
boolean immuneWarned = false;
|
||||
|
||||
protected boolean isNearYog(){
|
||||
int yogPos = Dungeon.level.exit + 3*Dungeon.level.width();
|
||||
return Dungeon.level.distance(pos, yogPos) <= 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
if (isNearYog()){
|
||||
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
|
||||
if (!immuneWarned){
|
||||
immuneWarned = true;
|
||||
GLog.w(Messages.get(this, "immune_hint"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.damage(dmg, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
|
||||
|
@ -122,9 +144,8 @@ public abstract class YogFist extends Mob {
|
|||
}
|
||||
|
||||
@Override
|
||||
//TODO different for some fists perhaps?
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 26, 32 );
|
||||
return Random.NormalIntRange( 18, 36 );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -132,6 +153,25 @@ public abstract class YogFist extends Mob {
|
|||
return Random.NormalIntRange(0, 15);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return Messages.get(YogFist.class, "desc") + "\n\n" + Messages.get(this, "desc");
|
||||
}
|
||||
|
||||
public static final String RANGED_COOLDOWN = "ranged_cooldown";
|
||||
|
||||
@Override
|
||||
public void storeInBundle(Bundle bundle) {
|
||||
super.storeInBundle(bundle);
|
||||
bundle.put(RANGED_COOLDOWN, rangedCooldown);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
rangedCooldown = bundle.getFloat(RANGED_COOLDOWN);
|
||||
}
|
||||
|
||||
public static class Burning extends YogFist {
|
||||
|
||||
{
|
||||
|
@ -151,13 +191,11 @@ public abstract class YogFist extends Mob {
|
|||
CellEmitter.get( pos ).burst( Speck.factory( Speck.STEAM ), 10 );
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; i++){
|
||||
int cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)];
|
||||
if (Dungeon.level.map[cell] == Terrain.WATER){
|
||||
Level.set( cell, Terrain.EMPTY);
|
||||
GameScene.updateMap( cell );
|
||||
CellEmitter.get( cell ).burst( Speck.factory( Speck.STEAM ), 10 );
|
||||
}
|
||||
int cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)];
|
||||
if (Dungeon.level.map[cell] == Terrain.WATER){
|
||||
Level.set( cell, Terrain.EMPTY);
|
||||
GameScene.updateMap( cell );
|
||||
CellEmitter.get( cell ).burst( Speck.factory( Speck.STEAM ), 10 );
|
||||
}
|
||||
|
||||
for (int i : PathFinder.NEIGHBOURS9) {
|
||||
|
@ -174,27 +212,12 @@ public abstract class YogFist extends Mob {
|
|||
protected void zap() {
|
||||
spend( 1f );
|
||||
|
||||
if (hit( this, enemy, true )) {
|
||||
|
||||
int dmg = damageRoll()/2;
|
||||
//TODO damage source logic
|
||||
enemy.damage( dmg, this );
|
||||
Buff.affect( enemy, com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning.class ).reignite( enemy );
|
||||
|
||||
if (!enemy.isAlive() && enemy == Dungeon.hero) {
|
||||
Dungeon.fail( getClass() );
|
||||
GLog.n( Messages.get(Char.class, "kill", name()) );
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
enemy.sprite.showStatus( CharSprite.NEUTRAL, enemy.defenseVerb() );
|
||||
}
|
||||
|
||||
if (Dungeon.level.map[enemy.pos] == Terrain.WATER){
|
||||
Level.set( enemy.pos, Terrain.EMPTY);
|
||||
GameScene.updateMap( enemy.pos );
|
||||
CellEmitter.get( enemy.pos ).burst( Speck.factory( Speck.STEAM ), 10 );
|
||||
} else {
|
||||
Buff.affect( enemy, com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning.class ).reignite( enemy );
|
||||
}
|
||||
|
||||
for (int i : PathFinder.NEIGHBOURS9){
|
||||
|
@ -221,19 +244,17 @@ public abstract class YogFist extends Mob {
|
|||
|
||||
boolean result = super.act();
|
||||
|
||||
for (int i = 0; i < 2; i++){
|
||||
int cell = pos + PathFinder.NEIGHBOURS9[Random.Int(9)];
|
||||
if (Dungeon.level.map[cell] == Terrain.GRASS){
|
||||
Level.set( cell, Terrain.FURROWED_GRASS);
|
||||
GameScene.updateMap( cell );
|
||||
CellEmitter.get( cell ).burst( LeafParticle.GENERAL, 10 );
|
||||
}
|
||||
int cell = pos + PathFinder.NEIGHBOURS9[Random.Int(9)];
|
||||
if (Dungeon.level.map[cell] == Terrain.GRASS){
|
||||
Level.set( cell, Terrain.FURROWED_GRASS);
|
||||
GameScene.updateMap( cell );
|
||||
CellEmitter.get( cell ).burst( LeafParticle.GENERAL, 10 );
|
||||
}
|
||||
|
||||
Dungeon.observe();
|
||||
|
||||
for (int i : PathFinder.NEIGHBOURS9) {
|
||||
int cell = pos + i;
|
||||
cell = pos + i;
|
||||
if (canSpreadGrass(cell)){
|
||||
Level.set(pos+i, Terrain.GRASS);
|
||||
GameScene.updateMap( pos + i );
|
||||
|
@ -252,7 +273,7 @@ public abstract class YogFist extends Mob {
|
|||
grassCells++;
|
||||
}
|
||||
}
|
||||
if (grassCells > 0) dmg = Math.round(dmg * (9-grassCells)/9f);
|
||||
if (grassCells > 0) dmg = Math.round(dmg * (6-grassCells)/6f);
|
||||
|
||||
super.damage(dmg, src);
|
||||
}
|
||||
|
@ -263,9 +284,6 @@ public abstract class YogFist extends Mob {
|
|||
|
||||
if (hit( this, enemy, true )) {
|
||||
|
||||
int dmg = damageRoll()/2;
|
||||
//TODO damage source logic
|
||||
enemy.damage( dmg, this );
|
||||
Buff.affect( enemy, Roots.class, 3f );
|
||||
|
||||
if (!enemy.isAlive() && enemy == Dungeon.hero) {
|
||||
|
@ -326,13 +344,21 @@ public abstract class YogFist extends Mob {
|
|||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
if (isNearYog()){
|
||||
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
|
||||
if (!immuneWarned){
|
||||
immuneWarned = true;
|
||||
GLog.w(Messages.get(this, "immune_hint"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!(src instanceof Bleeding)){
|
||||
Bleeding b = buff(Bleeding.class);
|
||||
if (b == null){
|
||||
b = new Bleeding();
|
||||
}
|
||||
b.announced = false;
|
||||
b.set(dmg/3f);
|
||||
b.set(dmg*.67f);
|
||||
b.attachTo(this);
|
||||
sprite.showStatus(CharSprite.WARNING, b.toString() + " " + (int)b.level());
|
||||
} else{
|
||||
|
@ -373,8 +399,21 @@ public abstract class YogFist extends Mob {
|
|||
properties.add(Property.INORGANIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 20, 40 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
if (isNearYog()){
|
||||
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
|
||||
if (!immuneWarned){
|
||||
immuneWarned = true;
|
||||
GLog.w(Messages.get(this, "immune_hint"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!(src instanceof Viscosity.DeferedDamage)){
|
||||
Buff.affect(this, Viscosity.DeferedDamage.class).prolong(dmg);
|
||||
sprite.showStatus( CharSprite.WARNING, Messages.get(Viscosity.class, "deferred", dmg) );
|
||||
|
@ -386,7 +425,7 @@ public abstract class YogFist extends Mob {
|
|||
@Override
|
||||
protected void zap() {
|
||||
spend( 1f );
|
||||
Buff.affect(enemy, Cripple.class, 5f);
|
||||
Buff.affect(enemy, Cripple.class, 4f);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -406,16 +445,17 @@ public abstract class YogFist extends Mob {
|
|||
//ranged attack has no cooldown
|
||||
}
|
||||
|
||||
//used so resistances can differentiate between melee and magical attacks
|
||||
public static class LightBeam{}
|
||||
|
||||
@Override
|
||||
protected void zap() {
|
||||
spend( 1f );
|
||||
|
||||
if (hit( this, enemy, true )) {
|
||||
|
||||
int dmg = damageRoll()/2;
|
||||
//TODO damage source logic
|
||||
enemy.damage( dmg, this );
|
||||
Buff.prolong( enemy, Blindness.class, 5f );
|
||||
enemy.damage( damageRoll(), new LightBeam() );
|
||||
Buff.prolong( enemy, Blindness.class, 4f );
|
||||
|
||||
if (!enemy.isAlive() && enemy == Dungeon.hero) {
|
||||
Dungeon.fail( getClass() );
|
||||
|
@ -433,9 +473,9 @@ public abstract class YogFist extends Mob {
|
|||
public void damage(int dmg, Object src) {
|
||||
int beforeHP = HP;
|
||||
super.damage(dmg, src);
|
||||
if (beforeHP > HT/2 && HP < HT/2){
|
||||
if (isAlive() && beforeHP > HT/2 && HP < HT/2){
|
||||
HP = HT/2;
|
||||
Buff.prolong( enemy, Blindness.class, 50f );
|
||||
Buff.prolong( enemy, Blindness.class, 30f );
|
||||
int i;
|
||||
do {
|
||||
i = Random.Int(Dungeon.level.length());
|
||||
|
@ -443,6 +483,7 @@ public abstract class YogFist extends Mob {
|
|||
ScrollOfTeleportation.appear(this, i);
|
||||
state = WANDERING;
|
||||
GameScene.flash(0xFFFFFF);
|
||||
GLog.w( Messages.get( this, "teleport" ));
|
||||
} else if (!isAlive()){
|
||||
Buff.prolong( enemy, Blindness.class, 50f );
|
||||
GameScene.flash(0xFFFFFF);
|
||||
|
@ -464,15 +505,16 @@ public abstract class YogFist extends Mob {
|
|||
//ranged attack has no cooldown
|
||||
}
|
||||
|
||||
//used so resistances can differentiate between melee and magical attacks
|
||||
public static class DarkBolt{}
|
||||
|
||||
@Override
|
||||
protected void zap() {
|
||||
spend( 1f );
|
||||
|
||||
if (hit( this, enemy, true )) {
|
||||
|
||||
int dmg = damageRoll()/2;
|
||||
//TODO damage source logic
|
||||
enemy.damage( dmg, this );
|
||||
enemy.damage( damageRoll(), new DarkBolt() );
|
||||
|
||||
Light l = enemy.buff(Light.class);
|
||||
if (l != null){
|
||||
|
@ -495,7 +537,7 @@ public abstract class YogFist extends Mob {
|
|||
public void damage(int dmg, Object src) {
|
||||
int beforeHP = HP;
|
||||
super.damage(dmg, src);
|
||||
if (beforeHP > HT/2 && HP < HT/2){
|
||||
if (isAlive() && beforeHP > HT/2 && HP < HT/2){
|
||||
HP = HT/2;
|
||||
Light l = Dungeon.hero.buff(Light.class);
|
||||
if (l != null){
|
||||
|
@ -508,6 +550,7 @@ public abstract class YogFist extends Mob {
|
|||
ScrollOfTeleportation.appear(this, i);
|
||||
state = WANDERING;
|
||||
GameScene.flash(0, false);
|
||||
GLog.w( Messages.get( this, "teleport" ));
|
||||
} else if (!isAlive()){
|
||||
Light l = Dungeon.hero.buff(Light.class);
|
||||
if (l != null){
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.DM100;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Shaman;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Warlock;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Yog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.YogFist;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlastWave;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfDisintegration;
|
||||
|
@ -81,6 +82,8 @@ public class AntiMagic extends Armor.Glyph {
|
|||
RESISTS.add( Warlock.DarkBolt.class );
|
||||
RESISTS.add( Eye.DeathGaze.class );
|
||||
RESISTS.add( Yog.BurningFist.DarkBolt.class );
|
||||
RESISTS.add( YogFist.Bright.LightBeam.class );
|
||||
RESISTS.add( YogFist.Dark.DarkBolt.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -748,11 +748,35 @@ actors.mobs.yog$larva.desc=Yog-Dzewa is an Old God, a powerful entity from the r
|
|||
actors.mobs.yogdzewa.name=Yog-Dzewa
|
||||
actors.mobs.yogdzewa.notice=I. SEE. YOU.
|
||||
actors.mobs.yogdzewa.immune=IMMUNE
|
||||
actors.mobs.yogdzewa.darkness=The shadows pull in closer.
|
||||
actors.mobs.yogdzewa.darkness=The darkness pulls in closer...
|
||||
actors.mobs.yogdzewa.hope=YOUR. HOPE. IS. AN. ILLUSION!
|
||||
actors.mobs.yogdzewa.defeated=...
|
||||
actors.mobs.yogdzewa.rankings_desc=Devoured by Yog-Dzewa
|
||||
actors.mobs.yogdzewa.desc=TODO
|
||||
actors.mobs.yogdzewa.desc=Yog-Dzewa is an Old God; a great monstrosity which reaches into mortal worlds and devours them to fuel its endless growth. The dwarves must have attracted the attention of this cosmic horror while toying with dark magics, and have been trying to keep it contained ever since.\n\nYog-Dzewa originates from a dimension of raw magical chaos, and cannot bring its true form into this world. Instead it has created avatars and summoned demonic minions to do its bidding here.\n\nThis giant eye is the focal point of Yog-Dzewa's power in this world. While the eye itself is immobile, it is capable of shooting powerful beams of demonic magic and summoning a variety of minions to aid it.
|
||||
actors.mobs.yogdzewa.desc_spawners=You can feel waves of demonic energy radiating to the eye from the floors above. Something you left alive up there must be funneling power back into Yog-Dzewa. _Yog will use this energy to summon more powerful minions!_
|
||||
actors.mobs.yogdzewa$larva.name=god's larva
|
||||
actors.mobs.yogdzewa$larva.rankings_desc=Devoured by Yog-Dzewa
|
||||
actors.mobs.yogdzewa$larva.desc=These tiny spawn of Yog-Dzewa are simple minions that are easy to produce. While individually weak, they are summoned quickly and can become overwhelming in large numbers.
|
||||
actors.mobs.yogdzewa$yogripper.rankings_desc=Devoured by Yog-Dzewa
|
||||
|
||||
actors.mobs.yogfist.immune=IMMUNE
|
||||
actors.mobs.yogfist.immune_hint=The fist is immune while near to the eye!
|
||||
actors.mobs.yogfist.rankings_desc=Devoured by Yog-Dzewa
|
||||
actors.mobs.yogfist.desc=This fist is an aspect of Yog-Dzewa's power. Fists are linked to the power of Yog-Dzewa, and will be protected from all damage when they are close to the eye.
|
||||
actors.mobs.yogfist$burning.name=burning fist
|
||||
actors.mobs.yogfist$burning.desc=This fist is formed out of chaotic fiery magic. As it moves it will constantly set terrain around it ablaze. It is also capable of shooting blasts of fiery power, which spread flames where the impact.\n\nThe fist's ability to spread flames is suppressed when near water, but it's heat is so great that any water around it will evaporate after a short while!
|
||||
actors.mobs.yogfist$soiled.name=soiled fist
|
||||
actors.mobs.yogfist$soiled.desc=This fist is formed out of chaotic earthen magic. As it moves it will constantly cause vegetation to sprout around it. It can also shoot concentrated earthen blasts that will ensnare its target in rapidly growing vines and roots!\n\nThe fist derives power from this plant life, and will resist damage based on the amount of tall or furrowed vegetation near it!
|
||||
actors.mobs.yogfist$rotting.name=rotting fist
|
||||
actors.mobs.yogfist$rotting.desc=This fist is formed out of living corruption. It is a towering mass of decaying flesh that can spread caustic ooze in melee and toxic gas at range. Even worse, the fist's great mass causes it to bleed instead of taking damage directly.\n\nWater can be used to wash the ooze off, but the fist is also capable of adsorbing water to heal itself! Additionally, damaging the fist while it is bleeding will cause the bleed to refresh, but not stack!
|
||||
actors.mobs.yogfist$rusted.name=rusted fist
|
||||
actors.mobs.yogfist$rusted.desc=This fist is formed out of living metal. It is a towering mass of shifting metal that has powerful melee attacks, and can cripple its targets at range. Because of its tremendous mass, the fist will take any damage dealt to it over time, instead of immediately.\n\nThe fist is inflexible however, and cannot move into tight passageways. Additionally, while it make take damage slowly, the deferred damage will continue to increase if the fist is hit multiple times.
|
||||
actors.mobs.yogfist$bright.name=bright fist
|
||||
actors.mobs.yogfist$bright.teleport=The fist teleports away in a flash of light that seriously blinds you!
|
||||
actors.mobs.yogfist$bright.desc=This fist is formed out of pure light energy. It is capable of shooting powerful rays of searing light every turn! These beams will temporarily blind you in addition to dealing heavy damage. The fist is also capable of briefly engulphing the arena in blinding light in order to escape!\n\nThe fist has no special abilities which it can use in melee range however.
|
||||
actors.mobs.yogfist$dark.name=dark fist
|
||||
actors.mobs.yogfist$dark.teleport=The fist teleports away in a blast of darkness that extinguishes your light source!
|
||||
actors.mobs.yogfist$dark.desc=This fist is formed out of pure dark energy. It is capable of shooting powerful blasts of dark magic every turn! These blasts will weaken your light source in addition to dealing heavy damage. The fist is also capable of briefly engulfing the arena in darkness in order to escape!\n\nThe fist has no special abilities which it can use in melee range however.
|
||||
|
||||
|
||||
actors.char.kill=%s killed you...
|
||||
|
|
|
@ -1585,7 +1585,7 @@ items.weapon.weapon$enchantment.enchant=enchantment
|
|||
items.amulet.name=amulet of yendor
|
||||
items.amulet.ac_end=END THE GAME
|
||||
items.amulet.rankings_desc=Obtained the Amulet of Yendor
|
||||
items.amulet.desc=The Amulet of Yendor is the most powerful known artifact of unknown origin. It is said that the amulet is able to fulfil any wish if its owner's will-power is strong enough to "persuade" it to do it.
|
||||
items.amulet.desc=The Amulet of Yendor is the most powerful artifact known to human or dwarf kind. Its shimmering crystals contain incredible and wondrous power.\n\nThe origins of the amulet are unknown. History says that the King of Dwarves boasted that he had discovered the artifact shortly before the Dwarven civilization cut off all contact. How did he find it? How did Yog-Dzewa take it from him? Questions for another time perhaps, all that matters now is the amulet is yours!
|
||||
|
||||
items.ankh.name=ankh
|
||||
items.ankh.ac_bless=BLESS
|
||||
|
|
|
@ -8,7 +8,7 @@ scenes.alchemyscene.energy=Alchemical Energy: %d
|
|||
|
||||
scenes.amuletscene.exit=Let's call it a day
|
||||
scenes.amuletscene.stay=I'm not done yet
|
||||
scenes.amuletscene.text=You finally hold it in your hands, the Amulet of Yendor. Using its power you can take over the world or bring peace and prosperity to people or whatever. Anyway, your life will change forever and this game will end here. Or you can stay a mere mortal a little longer.
|
||||
scenes.amuletscene.text=You finally hold it in your hands, the Amulet of Yendor! With the power of this amulet nothing will be able to stand in your way! You have conquered the dungeon and succeeded in your quest!\n\nOr, perhaps you're not ready yet? You can also decide to just hold onto the amulet, and stay a mere mortal a little longer...
|
||||
|
||||
scenes.badgesscene.title=Your Badges
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user