v0.8.0: rough implementation for Yog's fists and Yog fight progression
This commit is contained in:
parent
b1f7023d78
commit
3c4e8a5f74
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 3.9 KiB |
|
@ -39,6 +39,10 @@ public class Bleeding extends Buff {
|
|||
}
|
||||
|
||||
protected float level;
|
||||
|
||||
public float level(){
|
||||
return level;
|
||||
}
|
||||
|
||||
private static final String LEVEL = "level";
|
||||
|
||||
|
|
|
@ -56,6 +56,10 @@ public class Light extends FlavourBuff {
|
|||
Dungeon.observe();
|
||||
super.detach();
|
||||
}
|
||||
|
||||
public void weaken( int amount ){
|
||||
spend(-amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int icon() {
|
||||
|
|
|
@ -21,23 +21,213 @@
|
|||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
||||
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
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.Light;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.LockedFloor;
|
||||
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.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
|
||||
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.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.ui.BossHealthBar;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
import com.watabou.utils.Reflection;
|
||||
|
||||
//TODO boss implementation
|
||||
public class YogDzewa extends Yog {
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class YogDzewa extends Mob {
|
||||
|
||||
{
|
||||
HP = HT = 1;
|
||||
spriteClass = YogSprite.class;
|
||||
|
||||
HP = HT = 600;
|
||||
|
||||
EXP = 50;
|
||||
|
||||
state = PASSIVE;
|
||||
|
||||
properties.add(Property.BOSS);
|
||||
properties.add(Property.IMMOVABLE);
|
||||
properties.add(Property.DEMONIC);
|
||||
}
|
||||
|
||||
private int phase = 0;
|
||||
private Class[] toSummon = new Class[3];
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
public void damage( int dmg, Object src ) {
|
||||
|
||||
super.die( cause );
|
||||
if (findFist() != null){
|
||||
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
|
||||
return;
|
||||
}
|
||||
|
||||
super.damage( dmg, src );
|
||||
|
||||
if (phase < 3 && HP <= HT * (3 - phase)/4f){
|
||||
Dungeon.level.viewDistance--;
|
||||
if (Dungeon.hero.buff(Light.class) == null){
|
||||
Dungeon.hero.viewDistance = Dungeon.level.viewDistance;
|
||||
}
|
||||
Dungeon.observe();
|
||||
GLog.n(Messages.get(this, "darkness"));
|
||||
sprite.showStatus(CharSprite.POSITIVE, Messages.get(this, "immune"));
|
||||
|
||||
YogFist fist = (YogFist) Reflection.newInstance(toSummon[phase]);
|
||||
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);
|
||||
|
||||
int targetPos = Dungeon.level.exit + Dungeon.level.width();
|
||||
if (Actor.findChar(targetPos) == null){
|
||||
fist.pos = targetPos;
|
||||
} else if (Actor.findChar(targetPos-1) == null){
|
||||
fist.pos = targetPos-1;
|
||||
} else if (Actor.findChar(targetPos+1) == null){
|
||||
fist.pos = targetPos+1;
|
||||
}
|
||||
|
||||
GameScene.add(fist, 1);
|
||||
Actor.addDelayed( new Pushing( fist, Dungeon.level.exit, fist.pos ), -1 );
|
||||
phase++;
|
||||
}
|
||||
|
||||
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
|
||||
if (lock != null) lock.addTime(dmg);
|
||||
|
||||
Dungeon.level.unseal();
|
||||
Dungeon.level.heaps.get(pos).destroy();
|
||||
}
|
||||
|
||||
private YogFist findFist(){
|
||||
for ( Char c : Actor.chars() ){
|
||||
if (c instanceof YogFist){
|
||||
return (YogFist) c;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beckon( int cell ) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
for (Mob mob : (Iterable<Mob>)Dungeon.level.mobs.clone()) {
|
||||
if (mob instanceof Larva || mob instanceof RipperDemon) {
|
||||
mob.die( cause );
|
||||
}
|
||||
}
|
||||
|
||||
Dungeon.level.viewDistance = 4;
|
||||
if (Dungeon.hero.buff(Light.class) == null){
|
||||
Dungeon.hero.viewDistance = Dungeon.level.viewDistance;
|
||||
}
|
||||
|
||||
GameScene.bossSlain();
|
||||
Dungeon.level.unseal();
|
||||
super.die( cause );
|
||||
|
||||
yell( Messages.get(this, "defeated") );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notice() {
|
||||
super.notice();
|
||||
if (!BossHealthBar.isAssigned()) {
|
||||
BossHealthBar.assignBoss(this);
|
||||
yell(Messages.get(this, "notice"));
|
||||
for (Char ch : Actor.chars()){
|
||||
if (ch instanceof DriedRose.GhostHero){
|
||||
GLog.n("\n");
|
||||
((DriedRose.GhostHero) ch).sayBoss();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
BossHealthBar.assignBoss(this);
|
||||
}
|
||||
|
||||
public static class Larva extends Mob {
|
||||
|
||||
{
|
||||
spriteClass = LarvaSprite.class;
|
||||
|
||||
HP = HT = 25;
|
||||
defenseSkill = 20;
|
||||
|
||||
EXP = 5;
|
||||
maxLvl = -2;
|
||||
|
||||
state = HUNTING;
|
||||
|
||||
properties.add(Property.DEMONIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 22, 30 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drRoll() {
|
||||
return Random.NormalIntRange(0, 8);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,522 @@
|
|||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2020 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.mobs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Fire;
|
||||
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;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.armor.glyphs.Viscosity;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
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.utils.GLog;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public abstract class YogFist extends Mob {
|
||||
|
||||
{
|
||||
HP = HT = 300;
|
||||
defenseSkill = 25;
|
||||
|
||||
//for doomed resistance
|
||||
EXP = 25;
|
||||
maxLvl = -2;
|
||||
|
||||
state = WANDERING;
|
||||
|
||||
properties.add(Property.BOSS);
|
||||
properties.add(Property.DEMONIC);
|
||||
}
|
||||
|
||||
private float rangedCooldown;
|
||||
protected boolean canRangedInMelee = true;
|
||||
|
||||
protected void incrementRangedCooldown(){
|
||||
rangedCooldown += Random.NormalFloat(6, 9);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
if (paralysed <= 0 && rangedCooldown > 0) rangedCooldown--;
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack(Char enemy) {
|
||||
if (rangedCooldown <= 0){
|
||||
return new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
|
||||
} else {
|
||||
return super.canAttack(enemy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
|
||||
if (Dungeon.level.adjacent( pos, enemy.pos ) && (!canRangedInMelee || rangedCooldown > 0)) {
|
||||
|
||||
return super.doAttack( enemy );
|
||||
|
||||
} else {
|
||||
|
||||
incrementRangedCooldown();
|
||||
if (sprite != null && (sprite.visible || enemy.sprite.visible)) {
|
||||
sprite.zap( enemy.pos );
|
||||
return false;
|
||||
} else {
|
||||
zap();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void zap();
|
||||
|
||||
public void onZapComplete(){
|
||||
zap();
|
||||
next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 36;
|
||||
}
|
||||
|
||||
@Override
|
||||
//TODO different for some fists perhaps?
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 26, 32 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drRoll() {
|
||||
return Random.NormalIntRange(0, 15);
|
||||
}
|
||||
|
||||
public static class Burning extends YogFist {
|
||||
|
||||
{
|
||||
spriteClass = FistSprite.Burning.class;
|
||||
|
||||
properties.add(Property.FIERY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean act() {
|
||||
|
||||
boolean result = super.act();
|
||||
|
||||
if (Dungeon.level.map[pos] == Terrain.WATER){
|
||||
Level.set( pos, Terrain.EMPTY);
|
||||
GameScene.updateMap( pos );
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
for (int i : PathFinder.NEIGHBOURS9) {
|
||||
int vol = Fire.volumeAt(pos+i, Fire.class);
|
||||
if (vol < 4 && !Dungeon.level.water[pos + i] && !Dungeon.level.solid[pos + i]){
|
||||
GameScene.add( Blob.seed( pos + i, 4 - vol, Fire.class ) );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
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 );
|
||||
}
|
||||
|
||||
for (int i : PathFinder.NEIGHBOURS9){
|
||||
if (!Dungeon.level.water[enemy.pos+i] && !Dungeon.level.solid[enemy.pos+i]){
|
||||
int vol = Fire.volumeAt(enemy.pos+i, Fire.class);
|
||||
if (vol < 4){
|
||||
GameScene.add( Blob.seed( enemy.pos + i, 4 - vol, Fire.class ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Soiled extends YogFist {
|
||||
|
||||
{
|
||||
spriteClass = FistSprite.Soiled.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean act() {
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
Dungeon.observe();
|
||||
|
||||
for (int i : PathFinder.NEIGHBOURS9) {
|
||||
int cell = pos + i;
|
||||
if (canSpreadGrass(cell)){
|
||||
Level.set(pos+i, Terrain.GRASS);
|
||||
GameScene.updateMap( pos + i );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
int grassCells = 0;
|
||||
for (int i : PathFinder.NEIGHBOURS9) {
|
||||
if (Dungeon.level.map[pos+i] == Terrain.FURROWED_GRASS
|
||||
|| Dungeon.level.map[pos+i] == Terrain.HIGH_GRASS){
|
||||
grassCells++;
|
||||
}
|
||||
}
|
||||
if (grassCells > 0) dmg = Math.round(dmg * (9-grassCells)/9f);
|
||||
|
||||
super.damage(dmg, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
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, Roots.class, 3f );
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
for (int i : PathFinder.NEIGHBOURS9){
|
||||
int cell = enemy.pos + i;
|
||||
if (canSpreadGrass(cell)){
|
||||
if (Random.Int(5) == 0){
|
||||
Level.set(cell, Terrain.FURROWED_GRASS);
|
||||
GameScene.updateMap( cell );
|
||||
} else {
|
||||
Level.set(cell, Terrain.GRASS);
|
||||
GameScene.updateMap( cell );
|
||||
}
|
||||
CellEmitter.get( cell ).burst( LeafParticle.GENERAL, 10 );
|
||||
}
|
||||
}
|
||||
Dungeon.observe();
|
||||
|
||||
}
|
||||
|
||||
private boolean canSpreadGrass(int cell){
|
||||
int yogPos = Dungeon.level.exit + Dungeon.level.width()*3;
|
||||
return Dungeon.level.distance(cell, yogPos) > 4 && !Dungeon.level.solid[cell]
|
||||
&& !(Dungeon.level.map[cell] == Terrain.FURROWED_GRASS || Dungeon.level.map[cell] == Terrain.HIGH_GRASS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Rotting extends YogFist {
|
||||
|
||||
{
|
||||
spriteClass = FistSprite.Rotting.class;
|
||||
|
||||
properties.add(Property.ACIDIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
//ensures toxic gas acts at the appropriate time when added
|
||||
GameScene.add(Blob.seed(pos, 0, ToxicGas.class));
|
||||
|
||||
if (Dungeon.level.water[pos] && HP < HT) {
|
||||
sprite.emitter().burst( Speck.factory(Speck.HEALING), 3 );
|
||||
HP += HT/50;
|
||||
}
|
||||
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
if (!(src instanceof Bleeding)){
|
||||
Bleeding b = buff(Bleeding.class);
|
||||
if (b == null){
|
||||
b = new Bleeding();
|
||||
}
|
||||
b.announced = false;
|
||||
b.set(dmg/3f);
|
||||
b.attachTo(this);
|
||||
sprite.showStatus(CharSprite.WARNING, b.toString() + " " + (int)b.level());
|
||||
} else{
|
||||
super.damage(dmg, src);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void zap() {
|
||||
spend( 1f );
|
||||
GameScene.add(Blob.seed(enemy.pos, 100, ToxicGas.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
damage = super.attackProc( enemy, damage );
|
||||
|
||||
if (Random.Int( 2 ) == 0) {
|
||||
Buff.affect( enemy, Ooze.class ).set( 20f );
|
||||
enemy.sprite.burst( 0xFF000000, 5 );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
{
|
||||
immunities.add(ToxicGas.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Rusted extends YogFist {
|
||||
|
||||
{
|
||||
spriteClass = FistSprite.Rusted.class;
|
||||
|
||||
properties.add(Property.LARGE);
|
||||
properties.add(Property.INORGANIC);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
if (!(src instanceof Viscosity.DeferedDamage)){
|
||||
Buff.affect(this, Viscosity.DeferedDamage.class).prolong(dmg);
|
||||
sprite.showStatus( CharSprite.WARNING, Messages.get(Viscosity.class, "deferred", dmg) );
|
||||
} else{
|
||||
super.damage(dmg, src);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void zap() {
|
||||
spend( 1f );
|
||||
Buff.affect(enemy, Cripple.class, 5f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Bright extends YogFist {
|
||||
|
||||
{
|
||||
spriteClass = FistSprite.Bright.class;
|
||||
|
||||
properties.add(Property.ELECTRIC);
|
||||
|
||||
canRangedInMelee = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void incrementRangedCooldown() {
|
||||
//ranged attack has no cooldown
|
||||
}
|
||||
|
||||
@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 );
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
int beforeHP = HP;
|
||||
super.damage(dmg, src);
|
||||
if (beforeHP > HT/2 && HP < HT/2){
|
||||
HP = HT/2;
|
||||
Buff.prolong( enemy, Blindness.class, 50f );
|
||||
int i;
|
||||
do {
|
||||
i = Random.Int(Dungeon.level.length());
|
||||
} while (Dungeon.level.heroFOV[i] || Dungeon.level.solid[i] || Actor.findChar(i) != null);
|
||||
ScrollOfTeleportation.appear(this, i);
|
||||
state = WANDERING;
|
||||
GameScene.flash(0xFFFFFF);
|
||||
} else if (!isAlive()){
|
||||
Buff.prolong( enemy, Blindness.class, 50f );
|
||||
GameScene.flash(0xFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Dark extends YogFist {
|
||||
|
||||
{
|
||||
spriteClass = FistSprite.Dark.class;
|
||||
|
||||
canRangedInMelee = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void incrementRangedCooldown() {
|
||||
//ranged attack has no cooldown
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void zap() {
|
||||
spend( 1f );
|
||||
|
||||
if (hit( this, enemy, true )) {
|
||||
|
||||
int dmg = damageRoll()/2;
|
||||
//TODO damage source logic
|
||||
enemy.damage( dmg, this );
|
||||
|
||||
Light l = enemy.buff(Light.class);
|
||||
if (l != null){
|
||||
l.weaken(50);
|
||||
}
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
int beforeHP = HP;
|
||||
super.damage(dmg, src);
|
||||
if (beforeHP > HT/2 && HP < HT/2){
|
||||
HP = HT/2;
|
||||
Light l = Dungeon.hero.buff(Light.class);
|
||||
if (l != null){
|
||||
l.detach();
|
||||
}
|
||||
int i;
|
||||
do {
|
||||
i = Random.Int(Dungeon.level.length());
|
||||
} while (Dungeon.level.heroFOV[i] || Dungeon.level.solid[i] || Actor.findChar(i) != null);
|
||||
ScrollOfTeleportation.appear(this, i);
|
||||
state = WANDERING;
|
||||
GameScene.flash(0, false);
|
||||
} else if (!isAlive()){
|
||||
Light l = Dungeon.hero.buff(Light.class);
|
||||
if (l != null){
|
||||
l.detach();
|
||||
}
|
||||
GameScene.flash(0, false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -45,6 +45,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Bestiary;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mimic;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.YogFist;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Sheep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlowParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.WindParticle;
|
||||
|
@ -951,7 +952,8 @@ public abstract class Level implements Bundlable {
|
|||
if (sighted) {
|
||||
boolean[] blocking;
|
||||
|
||||
if (c instanceof Hero && ((Hero) c).subClass == HeroSubClass.WARDEN) {
|
||||
if ((c instanceof Hero && ((Hero) c).subClass == HeroSubClass.WARDEN)
|
||||
|| c instanceof YogFist.Soiled) {
|
||||
blocking = Dungeon.level.losBlocking.clone();
|
||||
for (int i = 0; i < blocking.length; i++){
|
||||
if (blocking[i] && (Dungeon.level.map[i] == Terrain.HIGH_GRASS || Dungeon.level.map[i] == Terrain.FURROWED_GRASS)){
|
||||
|
|
|
@ -27,7 +27,6 @@ import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.YogDzewa;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Yog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
|
||||
|
@ -164,7 +163,7 @@ public class NewHallsBossLevel extends Level {
|
|||
if (item != null) {
|
||||
int pos;
|
||||
do {
|
||||
pos = Random.IntRange( ROOM_LEFT, ROOM_RIGHT ) + Random.IntRange( ROOM_TOP + 1, ROOM_BOTTOM ) * width();
|
||||
pos = randomRespawnCell(null);
|
||||
} while (pos == entrance);
|
||||
drop( item, pos ).setHauntedIfCursed().type = Heap.Type.REMAINS;
|
||||
}
|
||||
|
@ -201,10 +200,9 @@ public class NewHallsBossLevel extends Level {
|
|||
|
||||
Dungeon.observe();
|
||||
|
||||
Yog boss = new YogDzewa();
|
||||
YogDzewa boss = new YogDzewa();
|
||||
boss.pos = exit + width*3;
|
||||
GameScene.add( boss );
|
||||
//boss.spawnFists();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -218,7 +216,6 @@ public class NewHallsBossLevel extends Level {
|
|||
CellEmitter.get(exit-1).burst(ShadowParticle.UP, 25);
|
||||
CellEmitter.get(exit).burst(ShadowParticle.UP, 100);
|
||||
CellEmitter.get(exit+1).burst(ShadowParticle.UP, 25);
|
||||
GameScene.flash(0);
|
||||
for( CustomTilemap t : customTiles){
|
||||
if (t instanceof CenterPieceVisuals){
|
||||
((CenterPieceVisuals) t).updateState();
|
||||
|
|
|
@ -930,11 +930,15 @@ public class GameScene extends PixelScene {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void flash( int color ) {
|
||||
scene.fadeIn( 0xFF000000 | color, true );
|
||||
flash( color, true);
|
||||
}
|
||||
|
||||
|
||||
public static void flash( int color, boolean lightmode ) {
|
||||
scene.fadeIn( 0xFF000000 | color, lightmode );
|
||||
}
|
||||
|
||||
public static void gameOver() {
|
||||
Banner gameOver = new Banner( BannerSprites.get( BannerSprites.Type.GAME_OVER ) );
|
||||
gameOver.show( 0x000000, 1f );
|
||||
|
|
|
@ -24,9 +24,16 @@ package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
|||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Yog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.YogFist;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Beam;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.CorrosionParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.SparkParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
|
||||
import com.watabou.noosa.Camera;
|
||||
import com.watabou.noosa.TextureFilm;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
|
@ -124,7 +131,12 @@ public abstract class FistSprite extends MobSprite {
|
|||
new Callback() {
|
||||
@Override
|
||||
public void call() {
|
||||
((Yog.BurningFist)ch).onZapComplete();
|
||||
//pre-0.8.0 saves
|
||||
if (ch instanceof Yog.BurningFist){
|
||||
((Yog.BurningFist)ch).onZapComplete();
|
||||
} else {
|
||||
((YogFist)ch).onZapComplete();
|
||||
}
|
||||
}
|
||||
} );
|
||||
Sample.INSTANCE.play( Assets.SND_ZAP );
|
||||
|
@ -160,12 +172,35 @@ public abstract class FistSprite extends MobSprite {
|
|||
|
||||
@Override
|
||||
public int blood() {
|
||||
return 0xFFFFBB33;
|
||||
return 0xFFFFDD34;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
public static class Soiled extends FistSprite {
|
||||
|
||||
{
|
||||
boltType = MagicMissile.FOLIAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int texOffset() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Emitter createEmitter() {
|
||||
Emitter emitter = emitter();
|
||||
emitter.pour( LeafParticle.GENERAL, 0.06f );
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int blood() {
|
||||
return 0xFF7F5424;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Rotting extends FistSprite {
|
||||
|
||||
|
@ -181,13 +216,96 @@ public abstract class FistSprite extends MobSprite {
|
|||
@Override
|
||||
protected Emitter createEmitter() {
|
||||
Emitter emitter = emitter();
|
||||
//emitter.pour( SewerLevel.WaterParticle.FACTORY, 0.06f );
|
||||
emitter.pour(Speck.factory(Speck.TOXIC), 0.25f );
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int blood() {
|
||||
return 0xFFFFBB33;
|
||||
return 0xFFB8BBA1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Rusted extends FistSprite {
|
||||
|
||||
{
|
||||
boltType = MagicMissile.CORROSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int texOffset() {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Emitter createEmitter() {
|
||||
Emitter emitter = emitter();
|
||||
emitter.pour(CorrosionParticle.MISSILE, 0.06f );
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int blood() {
|
||||
return 0xFF7F7F7F;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Bright extends FistSprite {
|
||||
|
||||
{
|
||||
boltType = MagicMissile.RAINBOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int texOffset() {
|
||||
return 40;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Emitter createEmitter() {
|
||||
Emitter emitter = emitter();
|
||||
emitter.pour(SparkParticle.STATIC, 0.06f );
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void zap( int cell ) {
|
||||
turnTo( ch.pos , cell );
|
||||
play( zap );
|
||||
|
||||
((YogFist)ch).onZapComplete();
|
||||
parent.add( new Beam.LightRay(center(), DungeonTilemap.raisedTileCenterToWorld(cell)));
|
||||
}
|
||||
@Override
|
||||
public int blood() {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Dark extends FistSprite {
|
||||
|
||||
{
|
||||
boltType = MagicMissile.SHADOW;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int texOffset() {
|
||||
return 50;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Emitter createEmitter() {
|
||||
Emitter emitter = emitter();
|
||||
emitter.pour(ShadowParticle.MISSILE, 0.06f );
|
||||
return emitter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int blood() {
|
||||
return 0xFF4A2F53;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -740,6 +740,14 @@ actors.mobs.yog$larva.name=god's larva
|
|||
actors.mobs.yog$larva.rankings_desc=Devoured by Yog-Dzewa
|
||||
actors.mobs.yog$larva.desc=Yog-Dzewa is an Old God, a powerful entity from the realms of chaos. A century ago, the ancient dwarves barely won the war against its army of demons, but were unable to kill the god itself. Instead, they then imprisoned it in the halls below their city, believing it to be too weak to rise ever again.
|
||||
|
||||
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.defeated=...
|
||||
actors.mobs.yogdzewa.rankings_desc=Devoured by Yog-Dzewa
|
||||
actors.mobs.yogdzewa.desc=TODO
|
||||
|
||||
|
||||
|
||||
actors.char.kill=%s killed you...
|
||||
|
|
Loading…
Reference in New Issue
Block a user