V0.1.0 Partial Commit
changed package and application names to differentiate from main PD release
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.AcidicSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Acidic extends Scorpio {
|
||||
|
||||
{
|
||||
name = "acidic scorpio";
|
||||
spriteClass = AcidicSprite.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc( Char enemy, int damage ) {
|
||||
|
||||
int dmg = Random.IntRange( 0, damage );
|
||||
if (dmg > 0) {
|
||||
enemy.damage( dmg, this );
|
||||
}
|
||||
|
||||
return super.defenseProc( enemy, damage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
Badges.validateRare( this );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Bleeding;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.AlbinoSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Albino extends Rat {
|
||||
|
||||
{
|
||||
name = "albino rat";
|
||||
spriteClass = AlbinoSprite.class;
|
||||
|
||||
HP = HT = 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
Badges.validateRare( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( 2 ) == 0) {
|
||||
Buff.affect( enemy, Bleeding.class ).set( damage );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Blindness;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.BanditSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Bandit extends Thief {
|
||||
|
||||
public Item item;
|
||||
|
||||
{
|
||||
name = "crazy bandit";
|
||||
spriteClass = BanditSprite.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean steal( Hero hero ) {
|
||||
if (super.steal( hero )) {
|
||||
|
||||
Buff.prolong( enemy, Blindness.class, Random.Int( 5, 12 ) );
|
||||
Dungeon.observe();
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
Badges.validateRare( this );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Leech;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.BatSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Bat extends Mob {
|
||||
|
||||
{
|
||||
name = "vampire bat";
|
||||
spriteClass = BatSprite.class;
|
||||
|
||||
HP = HT = 30;
|
||||
defenseSkill = 15;
|
||||
baseSpeed = 2f;
|
||||
|
||||
EXP = 7;
|
||||
maxLvl = 15;
|
||||
|
||||
flying = true;
|
||||
|
||||
loot = new PotionOfHealing();
|
||||
lootChance = 0.125f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 6, 12 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "evaded";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
|
||||
int reg = Math.min( damage, HT - HP );
|
||||
|
||||
if (reg > 0) {
|
||||
HP += reg;
|
||||
sprite.emitter().burst( Speck.factory( Speck.HEALING ), 1 );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"These brisk and tenacious inhabitants of cave domes may defeat much larger opponents by " +
|
||||
"replenishing their health with each successful attack.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( Leech.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.actors.Char;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Bestiary {
|
||||
|
||||
public static Mob mob( int depth ) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Mob> cl = (Class<? extends Mob>)mobClass( depth );
|
||||
try {
|
||||
return cl.newInstance();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Mob mutable( int depth ) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Mob> cl = (Class<? extends Mob>)mobClass( depth );
|
||||
|
||||
if (Random.Int( 30 ) == 0) {
|
||||
if (cl == Rat.class) {
|
||||
cl = Albino.class;
|
||||
} else if (cl == Thief.class) {
|
||||
cl = Bandit.class;
|
||||
} else if (cl == Brute.class) {
|
||||
cl = Shielded.class;
|
||||
} else if (cl == Monk.class) {
|
||||
cl = Senior.class;
|
||||
} else if (cl == Scorpio.class) {
|
||||
cl = Acidic.class;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return cl.newInstance();
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Class<?> mobClass( int depth ) {
|
||||
|
||||
float[] chances;
|
||||
Class<?>[] classes;
|
||||
|
||||
switch (depth) {
|
||||
case 1:
|
||||
chances = new float[]{ 1 };
|
||||
classes = new Class<?>[]{ Rat.class };
|
||||
break;
|
||||
case 2:
|
||||
chances = new float[]{ 1, 1 };
|
||||
classes = new Class<?>[]{ Rat.class, Gnoll.class };
|
||||
break;
|
||||
case 3:
|
||||
chances = new float[]{ 1, 2, 1, 0.02f };
|
||||
classes = new Class<?>[]{ Rat.class, Gnoll.class, Crab.class, Swarm.class };
|
||||
break;
|
||||
case 4:
|
||||
chances = new float[]{ 1, 2, 3, 0.02f, 0.01f, 0.01f };
|
||||
classes = new Class<?>[]{ Rat.class, Gnoll.class, Crab.class, Swarm.class, Skeleton.class, Thief.class };
|
||||
break;
|
||||
|
||||
case 5:
|
||||
chances = new float[]{ 1 };
|
||||
classes = new Class<?>[]{ Goo.class };
|
||||
break;
|
||||
|
||||
case 6:
|
||||
chances = new float[]{ 4, 2, 1, 0.2f };
|
||||
classes = new Class<?>[]{ Skeleton.class, Thief.class, Swarm.class, Shaman.class };
|
||||
break;
|
||||
case 7:
|
||||
chances = new float[]{ 3, 1, 1, 1 };
|
||||
classes = new Class<?>[]{ Skeleton.class, Shaman.class, Thief.class, Swarm.class };
|
||||
break;
|
||||
case 8:
|
||||
chances = new float[]{ 3, 2, 1, 1, 1, 0.02f };
|
||||
classes = new Class<?>[]{ Skeleton.class, Shaman.class, Gnoll.class, Thief.class, Swarm.class, Bat.class };
|
||||
break;
|
||||
case 9:
|
||||
chances = new float[]{ 3, 3, 1, 1, 0.02f, 0.01f };
|
||||
classes = new Class<?>[]{ Skeleton.class, Shaman.class, Thief.class, Swarm.class, Bat.class, Brute.class };
|
||||
break;
|
||||
|
||||
case 10:
|
||||
chances = new float[]{ 1 };
|
||||
classes = new Class<?>[]{ Tengu.class };
|
||||
break;
|
||||
|
||||
case 11:
|
||||
chances = new float[]{ 1, 0.2f };
|
||||
classes = new Class<?>[]{ Bat.class, Brute.class };
|
||||
break;
|
||||
case 12:
|
||||
chances = new float[]{ 1, 1, 0.2f };
|
||||
classes = new Class<?>[]{ Bat.class, Brute.class, Spinner.class };
|
||||
break;
|
||||
case 13:
|
||||
chances = new float[]{ 1, 3, 1, 1, 0.02f };
|
||||
classes = new Class<?>[]{ Bat.class, Brute.class, Shaman.class, Spinner.class, Elemental.class };
|
||||
break;
|
||||
case 14:
|
||||
chances = new float[]{ 1, 3, 1, 4, 0.02f, 0.01f };
|
||||
classes = new Class<?>[]{ Bat.class, Brute.class, Shaman.class, Spinner.class, Elemental.class, Monk.class };
|
||||
break;
|
||||
|
||||
case 15:
|
||||
chances = new float[]{ 1 };
|
||||
classes = new Class<?>[]{ DM300.class };
|
||||
break;
|
||||
|
||||
case 16:
|
||||
chances = new float[]{ 1, 1, 0.2f };
|
||||
classes = new Class<?>[]{ Elemental.class, Warlock.class, Monk.class };
|
||||
break;
|
||||
case 17:
|
||||
chances = new float[]{ 1, 1, 1 };
|
||||
classes = new Class<?>[]{ Elemental.class, Monk.class, Warlock.class };
|
||||
break;
|
||||
case 18:
|
||||
chances = new float[]{ 1, 2, 1, 1 };
|
||||
classes = new Class<?>[]{ Elemental.class, Monk.class, Golem.class, Warlock.class };
|
||||
break;
|
||||
case 19:
|
||||
chances = new float[]{ 1, 2, 3, 1, 0.02f };
|
||||
classes = new Class<?>[]{ Elemental.class, Monk.class, Golem.class, Warlock.class, Succubus.class };
|
||||
break;
|
||||
|
||||
case 20:
|
||||
chances = new float[]{ 1 };
|
||||
classes = new Class<?>[]{ King.class };
|
||||
break;
|
||||
|
||||
case 22:
|
||||
chances = new float[]{ 1, 1 };
|
||||
classes = new Class<?>[]{ Succubus.class, Eye.class };
|
||||
break;
|
||||
case 23:
|
||||
chances = new float[]{ 1, 2, 1 };
|
||||
classes = new Class<?>[]{ Succubus.class, Eye.class, Scorpio.class };
|
||||
break;
|
||||
case 24:
|
||||
chances = new float[]{ 1, 2, 3 };
|
||||
classes = new Class<?>[]{ Succubus.class, Eye.class, Scorpio.class };
|
||||
break;
|
||||
|
||||
case 25:
|
||||
chances = new float[]{ 1 };
|
||||
classes = new Class<?>[]{ Yog.class };
|
||||
break;
|
||||
|
||||
default:
|
||||
chances = new float[]{ 1 };
|
||||
classes = new Class<?>[]{ Eye.class };
|
||||
}
|
||||
|
||||
return classes[ Random.chances( chances )];
|
||||
}
|
||||
|
||||
public static boolean isUnique( Char mob ) {
|
||||
return mob instanceof Goo || mob instanceof Tengu || mob instanceof DM300 || mob instanceof King || mob instanceof Yog;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.BruteSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Brute extends Mob {
|
||||
|
||||
private static final String TXT_ENRAGED = "%s becomes enraged!";
|
||||
|
||||
{
|
||||
name = "gnoll brute";
|
||||
spriteClass = BruteSprite.class;
|
||||
|
||||
HP = HT = 40;
|
||||
defenseSkill = 15;
|
||||
|
||||
EXP = 8;
|
||||
maxLvl = 15;
|
||||
|
||||
loot = Gold.class;
|
||||
lootChance = 0.5f;
|
||||
}
|
||||
|
||||
private boolean enraged = false;
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
super.restoreFromBundle( bundle );
|
||||
enraged = HP < HT / 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return enraged ?
|
||||
Random.NormalIntRange( 10, 40 ) :
|
||||
Random.NormalIntRange( 8, 18 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
super.damage( dmg, src );
|
||||
|
||||
if (isAlive() && !enraged && HP < HT / 4) {
|
||||
enraged = true;
|
||||
spend( TICK );
|
||||
if (Dungeon.visible[pos]) {
|
||||
GLog.w( TXT_ENRAGED, name );
|
||||
sprite.showStatus( CharSprite.NEGATIVE, "enraged" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Brutes are the largest, strongest and toughest of all gnolls. When severely wounded, " +
|
||||
"they go berserk, inflicting even more damage to their enemies.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Terror.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.MysteryMeat;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CrabSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Crab extends Mob {
|
||||
|
||||
{
|
||||
name = "sewer crab";
|
||||
spriteClass = CrabSprite.class;
|
||||
|
||||
HP = HT = 15;
|
||||
defenseSkill = 5;
|
||||
baseSpeed = 2f;
|
||||
|
||||
EXP = 3;
|
||||
maxLvl = 9;
|
||||
|
||||
loot = new MysteryMeat();
|
||||
lootChance = 0.167f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 3, 6 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "parried";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
Ghost.Quest.process( pos );
|
||||
super.die( cause );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"These huge crabs are at the top of the food chain in the sewers. " +
|
||||
"They are extremely fast and their thick exoskeleton can withstand " +
|
||||
"heavy blows.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.Camera;
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||
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.ToxicGas;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfThorns;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.DM300Sprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class DM300 extends Mob {
|
||||
|
||||
{
|
||||
name = "DM-300";
|
||||
spriteClass = DM300Sprite.class;
|
||||
|
||||
HP = HT = 200;
|
||||
EXP = 30;
|
||||
defenseSkill = 18;
|
||||
|
||||
loot = new RingOfThorns().random();
|
||||
lootChance = 0.333f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 18, 24 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 28;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean act() {
|
||||
|
||||
GameScene.add( Blob.seed( pos, 30, ToxicGas.class ) );
|
||||
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move( int step ) {
|
||||
super.move( step );
|
||||
|
||||
if (Dungeon.level.map[step] == Terrain.INACTIVE_TRAP && HP < HT) {
|
||||
|
||||
HP += Random.Int( 1, HT - HP );
|
||||
sprite.emitter().burst( ElmoParticle.FACTORY, 5 );
|
||||
|
||||
if (Dungeon.visible[step] && Dungeon.hero.isAlive()) {
|
||||
GLog.n( "DM-300 repairs itself!" );
|
||||
}
|
||||
}
|
||||
|
||||
int[] cells = {
|
||||
step-1, step+1, step-Level.WIDTH, step+Level.WIDTH,
|
||||
step-1-Level.WIDTH,
|
||||
step-1+Level.WIDTH,
|
||||
step+1-Level.WIDTH,
|
||||
step+1+Level.WIDTH
|
||||
};
|
||||
int cell = cells[Random.Int( cells.length )];
|
||||
|
||||
if (Dungeon.visible[cell]) {
|
||||
CellEmitter.get( cell ).start( Speck.factory( Speck.ROCK ), 0.07f, 10 );
|
||||
Camera.main.shake( 3, 0.7f );
|
||||
Sample.INSTANCE.play( Assets.SND_ROCKS );
|
||||
|
||||
if (Level.water[cell]) {
|
||||
GameScene.ripple( cell );
|
||||
} else if (Dungeon.level.map[cell] == Terrain.EMPTY) {
|
||||
Level.set( cell, Terrain.EMPTY_DECO );
|
||||
GameScene.updateMap( cell );
|
||||
}
|
||||
}
|
||||
|
||||
Char ch = Actor.findChar( cell );
|
||||
if (ch != null && ch != this) {
|
||||
Buff.prolong( ch, Paralysis.class, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
super.die( cause );
|
||||
|
||||
GameScene.bossSlain();
|
||||
Dungeon.level.drop( new SkeletonKey( Dungeon.depth ), pos ).sprite.drop();
|
||||
|
||||
Badges.validateBossSlain();
|
||||
|
||||
yell( "Mission failed. Shutting down." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notice() {
|
||||
super.notice();
|
||||
yell( "Unauthorised personnel detected." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"This machine was created by the Dwarves several centuries ago. Later, Dwarves started to replace machines with " +
|
||||
"golems, elementals and even demons. Eventually it led their civilization to the decline. The DM-300 and similar " +
|
||||
"machines were typically used for construction and mining, and in some cases, for city defense.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( ToxicGas.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Frost;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfLiquidFlame;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfFirebolt;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Fire;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ElementalSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Elemental extends Mob {
|
||||
|
||||
{
|
||||
name = "fire elemental";
|
||||
spriteClass = ElementalSprite.class;
|
||||
|
||||
HP = HT = 65;
|
||||
defenseSkill = 20;
|
||||
|
||||
EXP = 10;
|
||||
maxLvl = 20;
|
||||
|
||||
flying = true;
|
||||
|
||||
loot = new PotionOfLiquidFlame();
|
||||
lootChance = 0.1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 16, 20 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 25;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( 2 ) == 0) {
|
||||
Buff.affect( enemy, Burning.class ).reignite( enemy );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
if (buff instanceof Burning) {
|
||||
if (HP < HT) {
|
||||
HP++;
|
||||
sprite.emitter().burst( Speck.factory( Speck.HEALING ), 1 );
|
||||
}
|
||||
} else {
|
||||
if (buff instanceof Frost) {
|
||||
damage( Random.NormalIntRange( 1, HT * 2 / 3 ), buff );
|
||||
}
|
||||
super.add( buff );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Wandering fire elementals are a byproduct of summoning greater entities. " +
|
||||
"They are too chaotic in their nature to be controlled by even the most powerful demonologist.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Burning.class );
|
||||
IMMUNITIES.add( Fire.class );
|
||||
IMMUNITIES.add( WandOfFirebolt.class );
|
||||
IMMUNITIES.add( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PurpleParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Dewdrop;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfDisintegration;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Leech;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.EyeSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Eye extends Mob {
|
||||
|
||||
private static final String TXT_DEATHGAZE_KILLED = "%s's deathgaze killed you...";
|
||||
|
||||
{
|
||||
name = "evil eye";
|
||||
spriteClass = EyeSprite.class;
|
||||
|
||||
HP = HT = 100;
|
||||
defenseSkill = 20;
|
||||
viewDistance = Light.DISTANCE;
|
||||
|
||||
EXP = 13;
|
||||
maxLvl = 25;
|
||||
|
||||
flying = true;
|
||||
|
||||
loot = new Dewdrop();
|
||||
lootChance = 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
private int hitCell;
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
|
||||
hitCell = Ballistica.cast( pos, enemy.pos, true, false );
|
||||
|
||||
for (int i=1; i < Ballistica.distance; i++) {
|
||||
if (Ballistica.trace[i] == enemy.pos) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float attackDelay() {
|
||||
return 1.6f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
|
||||
spend( attackDelay() );
|
||||
|
||||
boolean rayVisible = false;
|
||||
|
||||
for (int i=0; i < Ballistica.distance; i++) {
|
||||
if (Dungeon.visible[Ballistica.trace[i]]) {
|
||||
rayVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (rayVisible) {
|
||||
sprite.attack( hitCell );
|
||||
return false;
|
||||
} else {
|
||||
attack( enemy );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean attack( Char enemy ) {
|
||||
|
||||
for (int i=1; i < Ballistica.distance; i++) {
|
||||
|
||||
int pos = Ballistica.trace[i];
|
||||
|
||||
Char ch = Actor.findChar( pos );
|
||||
if (ch == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hit( this, ch, true )) {
|
||||
ch.damage( Random.NormalIntRange( 14, 20 ), this );
|
||||
|
||||
if (Dungeon.visible[pos]) {
|
||||
ch.sprite.flash();
|
||||
CellEmitter.center( pos ).burst( PurpleParticle.BURST, Random.IntRange( 1, 2 ) );
|
||||
}
|
||||
|
||||
if (!ch.isAlive() && ch == Dungeon.hero) {
|
||||
Dungeon.fail( Utils.format( ResultDescriptions.MOB, Utils.indefinite( name ), Dungeon.depth ) );
|
||||
GLog.n( TXT_DEATHGAZE_KILLED, name );
|
||||
}
|
||||
} else {
|
||||
ch.sprite.showStatus( CharSprite.NEUTRAL, ch.defenseVerb() );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"One of this demon's other names is \"orb of hatred\", because when it sees an enemy, " +
|
||||
"it uses its deathgaze recklessly, often ignoring its allies and wounding them.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( WandOfDisintegration.class );
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( Leech.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Terror.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.GnollSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Gnoll extends Mob {
|
||||
|
||||
{
|
||||
name = "gnoll scout";
|
||||
spriteClass = GnollSprite.class;
|
||||
|
||||
HP = HT = 12;
|
||||
defenseSkill = 4;
|
||||
|
||||
EXP = 2;
|
||||
maxLvl = 8;
|
||||
|
||||
loot = Gold.class;
|
||||
lootChance = 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 2, 5 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
Ghost.Quest.process( pos );
|
||||
super.die( cause );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Gnolls are hyena-like humanoids. They dwell in sewers and dungeons, venturing up to raid the surface from time to time. " +
|
||||
"Gnoll scouts are regular members of their pack, they are not as strong as brutes and not as intelligent as shamans.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.GolemSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Golem extends Mob {
|
||||
|
||||
{
|
||||
name = "golem";
|
||||
spriteClass = GolemSprite.class;
|
||||
|
||||
HP = HT = 85;
|
||||
defenseSkill = 18;
|
||||
|
||||
EXP = 12;
|
||||
maxLvl = 22;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 20, 40 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 28;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float attackDelay() {
|
||||
return 1.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "blocked";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
Imp.Quest.process( this );
|
||||
|
||||
super.die( cause );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"The Dwarves tried to combine their knowledge of mechanisms with their newfound power of elemental binding. " +
|
||||
"They used spirits of earth as the \"soul\" for the mechanical bodies of golems, which were believed to be " +
|
||||
"most controllable of all. Despite this, the tiniest mistake in the ritual could cause an outbreak.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Amok.class );
|
||||
IMMUNITIES.add( Terror.class );
|
||||
IMMUNITIES.add( Sleep.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.Camera;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Ooze;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.LloydsBeacon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.GooSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Goo extends Mob {
|
||||
|
||||
private static final float PUMP_UP_DELAY = 2f;
|
||||
|
||||
{
|
||||
name = "Goo";
|
||||
HP = HT = 80;
|
||||
EXP = 10;
|
||||
defenseSkill = 12;
|
||||
spriteClass = GooSprite.class;
|
||||
|
||||
loot = new LloydsBeacon();
|
||||
lootChance = 0.333f;
|
||||
}
|
||||
|
||||
private boolean pumpedUp = false;
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
if (pumpedUp) {
|
||||
return Random.NormalIntRange( 5, 30 );
|
||||
} else {
|
||||
return Random.NormalIntRange( 2, 12 );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return pumpedUp ? 30 : 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean act() {
|
||||
|
||||
if (Level.water[pos] && HP < HT) {
|
||||
sprite.emitter().burst( Speck.factory( Speck.HEALING ), 1 );
|
||||
HP++;
|
||||
}
|
||||
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return pumpedUp ? distance( enemy ) <= 2 : super.canAttack(enemy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( 3 ) == 0) {
|
||||
Buff.affect( enemy, Ooze.class );
|
||||
enemy.sprite.burst( 0x000000, 5 );
|
||||
}
|
||||
|
||||
if (pumpedUp) {
|
||||
Camera.main.shake( 3, 0.2f );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
if (pumpedUp || Random.Int( 3 ) > 0) {
|
||||
|
||||
return super.doAttack( enemy );
|
||||
|
||||
} else {
|
||||
|
||||
pumpedUp = true;
|
||||
spend( PUMP_UP_DELAY );
|
||||
|
||||
((GooSprite)sprite).pumpUp();
|
||||
|
||||
if (Dungeon.visible[pos]) {
|
||||
sprite.showStatus( CharSprite.NEGATIVE, "!!!" );
|
||||
GLog.n( "Goo is pumping itself up!" );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean attack( Char enemy ) {
|
||||
boolean result = super.attack( enemy );
|
||||
pumpedUp = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getCloser( int target ) {
|
||||
pumpedUp = false;
|
||||
return super.getCloser( target );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move( int step ) {
|
||||
((SewerBossLevel)Dungeon.level).seal();
|
||||
super.move( step );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
super.die( cause );
|
||||
|
||||
((SewerBossLevel)Dungeon.level).unseal();
|
||||
|
||||
GameScene.bossSlain();
|
||||
Dungeon.level.drop( new SkeletonKey( Dungeon.depth ), pos ).sprite.drop();
|
||||
|
||||
Badges.validateBossSlain();
|
||||
|
||||
yell( "glurp... glurp..." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notice() {
|
||||
super.notice();
|
||||
yell( "GLURP-GLURP!" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Little known about The Goo. It's quite possible that it is not even a creature, but rather a " +
|
||||
"conglomerate of substances from the sewers that gained rudiments of free will.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( ToxicGas.class );
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||
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.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.ArmorKit;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlink;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfDisintegration;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.CityBossLevel;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.KingSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.UndeadSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class King extends Mob {
|
||||
|
||||
private static final int MAX_ARMY_SIZE = 5;
|
||||
|
||||
{
|
||||
name = "King of Dwarves";
|
||||
spriteClass = KingSprite.class;
|
||||
|
||||
HP = HT = 300;
|
||||
EXP = 40;
|
||||
defenseSkill = 25;
|
||||
|
||||
Undead.count = 0;
|
||||
}
|
||||
|
||||
private boolean nextPedestal = true;
|
||||
|
||||
private static final String PEDESTAL = "pedestal";
|
||||
|
||||
@Override
|
||||
public void storeInBundle( Bundle bundle ) {
|
||||
super.storeInBundle( bundle );
|
||||
bundle.put( PEDESTAL, nextPedestal );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
super.restoreFromBundle( bundle );
|
||||
nextPedestal = bundle.getBoolean( PEDESTAL );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 20, 38 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 32;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "parried";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getCloser( int target ) {
|
||||
return canTryToSummon() ?
|
||||
super.getCloser( CityBossLevel.pedestal( nextPedestal ) ) :
|
||||
super.getCloser( target );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return canTryToSummon() ?
|
||||
pos == CityBossLevel.pedestal( nextPedestal ) :
|
||||
Level.adjacent( pos, enemy.pos );
|
||||
}
|
||||
|
||||
private boolean canTryToSummon() {
|
||||
if (Undead.count < maxArmySize()) {
|
||||
Char ch = Actor.findChar( CityBossLevel.pedestal( nextPedestal ) );
|
||||
return ch == this || ch == null;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean attack( Char enemy ) {
|
||||
if (canTryToSummon() && pos == CityBossLevel.pedestal( nextPedestal )) {
|
||||
summon();
|
||||
return true;
|
||||
} else {
|
||||
if (Actor.findChar( CityBossLevel.pedestal( nextPedestal ) ) == enemy) {
|
||||
nextPedestal = !nextPedestal;
|
||||
}
|
||||
return super.attack(enemy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
GameScene.bossSlain();
|
||||
Dungeon.level.drop( new ArmorKit(), pos ).sprite.drop();
|
||||
Dungeon.level.drop( new SkeletonKey( Dungeon.depth ), pos ).sprite.drop();
|
||||
|
||||
super.die( cause );
|
||||
|
||||
Badges.validateBossSlain();
|
||||
|
||||
yell( "You cannot kill me, " + Dungeon.hero.heroClass.title() + "... I am... immortal..." );
|
||||
}
|
||||
|
||||
private int maxArmySize() {
|
||||
return 1 + MAX_ARMY_SIZE * (HT - HP) / HT;
|
||||
}
|
||||
|
||||
private void summon() {
|
||||
|
||||
nextPedestal = !nextPedestal;
|
||||
|
||||
sprite.centerEmitter().start( Speck.factory( Speck.SCREAM ), 0.4f, 2 );
|
||||
Sample.INSTANCE.play( Assets.SND_CHALLENGE );
|
||||
|
||||
boolean[] passable = Level.passable.clone();
|
||||
for (Actor actor : Actor.all()) {
|
||||
if (actor instanceof Char) {
|
||||
passable[((Char)actor).pos] = false;
|
||||
}
|
||||
}
|
||||
|
||||
int undeadsToSummon = maxArmySize() - Undead.count;
|
||||
|
||||
PathFinder.buildDistanceMap( pos, passable, undeadsToSummon );
|
||||
PathFinder.distance[pos] = Integer.MAX_VALUE;
|
||||
int dist = 1;
|
||||
|
||||
undeadLabel:
|
||||
for (int i=0; i < undeadsToSummon; i++) {
|
||||
do {
|
||||
for (int j=0; j < Level.LENGTH; j++) {
|
||||
if (PathFinder.distance[j] == dist) {
|
||||
|
||||
Undead undead = new Undead();
|
||||
undead.pos = j;
|
||||
GameScene.add( undead );
|
||||
|
||||
WandOfBlink.appear( undead, j );
|
||||
new Flare( 3, 32 ).color( 0x000000, false ).show( undead.sprite, 2f ) ;
|
||||
|
||||
PathFinder.distance[j] = Integer.MAX_VALUE;
|
||||
|
||||
continue undeadLabel;
|
||||
}
|
||||
}
|
||||
dist++;
|
||||
} while (dist < undeadsToSummon);
|
||||
}
|
||||
|
||||
yell( "Arise, slaves!" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notice() {
|
||||
super.notice();
|
||||
yell( "How dare you!" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"The last king of dwarves was known for his deep understanding of processes of life and death. " +
|
||||
"He has persuaded members of his court to participate in a ritual, that should have granted them " +
|
||||
"eternal youthfulness. In the end he was the only one, who got it - and an army of undead " +
|
||||
"as a bonus.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( ToxicGas.class );
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
RESISTANCES.add( WandOfDisintegration.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Paralysis.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
|
||||
public static class Undead extends Mob {
|
||||
|
||||
public static int count = 0;
|
||||
|
||||
{
|
||||
name = "undead dwarf";
|
||||
spriteClass = UndeadSprite.class;
|
||||
|
||||
HP = HT = 28;
|
||||
defenseSkill = 15;
|
||||
|
||||
EXP = 0;
|
||||
|
||||
state = State.WANDERING;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdd() {
|
||||
count++;
|
||||
super.onAdd();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemove() {
|
||||
count--;
|
||||
super.onRemove();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 12, 16 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( MAX_ARMY_SIZE ) == 0) {
|
||||
Buff.prolong( enemy, Paralysis.class, 1 );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
super.damage( dmg, src );
|
||||
if (src instanceof ToxicGas) {
|
||||
((ToxicGas)src).clear( pos );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
|
||||
if (Dungeon.visible[pos]) {
|
||||
Sample.INSTANCE.play( Assets.SND_BONES );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "blocked";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"These undead dwarves, risen by the will of the King of Dwarves, were members of his court. " +
|
||||
"They appear as skeletons with a stunning amount of facial hair.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Death.class );
|
||||
IMMUNITIES.add( Paralysis.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Flare;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Wound;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public abstract class Mob extends Char {
|
||||
|
||||
private static final String TXT_DIED = "You hear something died in the distance";
|
||||
|
||||
protected static final String TXT_NOTICE1 = "?!";
|
||||
protected static final String TXT_RAGE = "#$%^";
|
||||
protected static final String TXT_EXP = "%+dEXP";
|
||||
|
||||
public enum State {
|
||||
SLEEPING,
|
||||
HUNTING,
|
||||
WANDERING,
|
||||
FLEEING,
|
||||
PASSIVE
|
||||
}
|
||||
public State state = State.SLEEPING;
|
||||
|
||||
public Class<? extends CharSprite> spriteClass;
|
||||
|
||||
protected int target = -1;
|
||||
|
||||
protected int defenseSkill = 0;
|
||||
|
||||
protected int EXP = 1;
|
||||
protected int maxLvl = 30;
|
||||
|
||||
protected Char enemy;
|
||||
protected boolean enemySeen;
|
||||
protected boolean alerted = false;
|
||||
|
||||
protected static final float TIME_TO_WAKE_UP = 1f;
|
||||
|
||||
public boolean hostile = true;
|
||||
|
||||
// Unreachable target
|
||||
public static final Mob DUMMY = new Mob() {
|
||||
{
|
||||
pos = -1;
|
||||
}
|
||||
};
|
||||
|
||||
private static final String STATE = "state";
|
||||
private static final String TARGET = "target";
|
||||
|
||||
@Override
|
||||
public void storeInBundle( Bundle bundle ) {
|
||||
|
||||
super.storeInBundle( bundle );
|
||||
|
||||
bundle.put( STATE, state.toString() );
|
||||
if (state != State.SLEEPING) {
|
||||
bundle.put( TARGET, target );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
|
||||
super.restoreFromBundle( bundle );
|
||||
|
||||
state = State.valueOf( bundle.getString( STATE ) );
|
||||
if (state != State.SLEEPING) {
|
||||
target = bundle.getInt( TARGET );
|
||||
}
|
||||
}
|
||||
|
||||
public CharSprite sprite() {
|
||||
CharSprite sprite = null;
|
||||
try {
|
||||
sprite = spriteClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return sprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
|
||||
super.act();
|
||||
|
||||
boolean alertedNow = alerted;
|
||||
alerted = false;
|
||||
|
||||
sprite.hideAlert();
|
||||
|
||||
if (paralysed) {
|
||||
enemySeen = false;
|
||||
spend( TICK );
|
||||
return true;
|
||||
}
|
||||
|
||||
enemy = chooseEnemy();
|
||||
|
||||
boolean enemyInFOV = enemy.isAlive() && Level.fieldOfView[enemy.pos] && enemy.invisible <= 0;
|
||||
|
||||
int oldPos = pos;
|
||||
|
||||
switch (state) {
|
||||
|
||||
case SLEEPING:
|
||||
if (enemyInFOV &&
|
||||
Random.Int( distance( enemy ) + enemy.stealth() + (enemy.flying ? 2 : 0) ) == 0) {
|
||||
|
||||
enemySeen = true;
|
||||
|
||||
notice();
|
||||
state = State.HUNTING;
|
||||
target = enemy.pos;
|
||||
|
||||
spend( TIME_TO_WAKE_UP );
|
||||
|
||||
} else {
|
||||
|
||||
enemySeen = false;
|
||||
|
||||
spend( TICK );
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
case WANDERING:
|
||||
if (enemyInFOV && (alertedNow || Random.Int( distance( enemy ) / 2 + enemy.stealth() ) == 0)) {
|
||||
|
||||
enemySeen = true;
|
||||
|
||||
notice();
|
||||
state = State.HUNTING;
|
||||
target = enemy.pos;
|
||||
|
||||
} else {
|
||||
|
||||
enemySeen = false;
|
||||
|
||||
if (target != -1 && getCloser( target )) {
|
||||
spend( 1 / speed() );
|
||||
return moveSprite( oldPos, pos );
|
||||
} else {
|
||||
target = Dungeon.level.randomDestination();
|
||||
spend( TICK );
|
||||
}
|
||||
|
||||
}
|
||||
return true;
|
||||
|
||||
case HUNTING:
|
||||
enemySeen = enemyInFOV;
|
||||
if (enemyInFOV && canAttack( enemy )) {
|
||||
|
||||
return doAttack( enemy );
|
||||
|
||||
} else {
|
||||
|
||||
if (enemyInFOV) {
|
||||
target = enemy.pos;
|
||||
}
|
||||
|
||||
if (target != -1 && getCloser( target )) {
|
||||
|
||||
|
||||
spend( 1 / speed() );
|
||||
return moveSprite( oldPos, pos );
|
||||
|
||||
} else {
|
||||
|
||||
spend( TICK );
|
||||
state = State.WANDERING;
|
||||
target = Dungeon.level.randomDestination(); // <--------
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
case FLEEING:
|
||||
enemySeen = enemyInFOV;
|
||||
if (enemyInFOV) {
|
||||
target = enemy.pos;
|
||||
}
|
||||
if (target != -1 && getFurther( target )) {
|
||||
|
||||
spend( 1 / speed() );
|
||||
return moveSprite( oldPos, pos );
|
||||
|
||||
} else {
|
||||
|
||||
spend( TICK );
|
||||
nowhereToRun();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case PASSIVE:
|
||||
enemySeen = false;
|
||||
spend( TICK );
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
protected Char chooseEnemy() {
|
||||
|
||||
if (buff( Amok.class ) != null) {
|
||||
if (enemy == Dungeon.hero || enemy == null) {
|
||||
|
||||
HashSet<Mob> enemies = new HashSet<Mob>();
|
||||
for (Mob mob:Dungeon.level.mobs) {
|
||||
if (mob != this && Level.fieldOfView[mob.pos]) {
|
||||
enemies.add( mob );
|
||||
}
|
||||
}
|
||||
if (enemies.size() > 0) {
|
||||
return Random.element( enemies );
|
||||
}
|
||||
|
||||
} else {
|
||||
return enemy;
|
||||
}
|
||||
}
|
||||
|
||||
Terror terror = (Terror)buff( Terror.class );
|
||||
if (terror != null) {
|
||||
return terror.source;
|
||||
}
|
||||
|
||||
return Dungeon.hero;
|
||||
}
|
||||
|
||||
protected void nowhereToRun() {
|
||||
}
|
||||
|
||||
protected boolean moveSprite( int from, int to ) {
|
||||
|
||||
if (sprite.isVisible() && (Dungeon.visible[from] || Dungeon.visible[to])) {
|
||||
sprite.move( from, to );
|
||||
return false;
|
||||
} else {
|
||||
sprite.place( to );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
super.add( buff );
|
||||
if (buff instanceof Amok) {
|
||||
if (sprite != null) {
|
||||
sprite.showStatus( CharSprite.NEGATIVE, TXT_RAGE );
|
||||
}
|
||||
state = State.HUNTING;
|
||||
} else if (buff instanceof Terror) {
|
||||
state = State.FLEEING;
|
||||
} else if (buff instanceof Sleep) {
|
||||
if (sprite != null) {
|
||||
new Flare( 4, 32 ).color( 0x44ffff, true ).show( sprite, 2f ) ;
|
||||
}
|
||||
state = State.SLEEPING;
|
||||
postpone( Sleep.SWS );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove( Buff buff ) {
|
||||
super.remove( buff );
|
||||
if (buff instanceof Terror) {
|
||||
sprite.showStatus( CharSprite.NEGATIVE, TXT_RAGE );
|
||||
state = State.HUNTING;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return Level.adjacent( pos, enemy.pos ) && !pacified;
|
||||
}
|
||||
|
||||
protected boolean getCloser( int target ) {
|
||||
|
||||
if (rooted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int step = Dungeon.findPath( this, pos, target,
|
||||
Level.passable,
|
||||
Level.fieldOfView );
|
||||
if (step != -1) {
|
||||
move( step );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean getFurther( int target ) {
|
||||
int step = Dungeon.flee( this, pos, target,
|
||||
Level.passable,
|
||||
Level.fieldOfView );
|
||||
if (step != -1) {
|
||||
move( step );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move( int step ) {
|
||||
super.move( step );
|
||||
|
||||
if (!flying) {
|
||||
Dungeon.level.mobPress( this );
|
||||
}
|
||||
}
|
||||
|
||||
protected float attackDelay() {
|
||||
return 1f;
|
||||
}
|
||||
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
|
||||
boolean visible = Dungeon.visible[pos];
|
||||
|
||||
if (visible) {
|
||||
sprite.attack( enemy.pos );
|
||||
} else {
|
||||
attack( enemy );
|
||||
}
|
||||
|
||||
spend( attackDelay() );
|
||||
|
||||
return !visible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttackComplete() {
|
||||
attack( enemy );
|
||||
super.onAttackComplete();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseSkill( Char enemy ) {
|
||||
return enemySeen && !paralysed ? defenseSkill : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc( Char enemy, int damage ) {
|
||||
if (!enemySeen && enemy == Dungeon.hero && ((Hero)enemy).subClass == HeroSubClass.ASSASSIN) {
|
||||
damage += Random.Int( 1, damage );
|
||||
Wound.hit( this );
|
||||
}
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
|
||||
Terror.recover( this );
|
||||
|
||||
if (state == State.SLEEPING) {
|
||||
state = State.WANDERING;
|
||||
}
|
||||
alerted = true;
|
||||
|
||||
super.damage( dmg, src );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
|
||||
super.destroy();
|
||||
|
||||
Dungeon.level.mobs.remove( this );
|
||||
|
||||
if (Dungeon.hero.isAlive()) {
|
||||
|
||||
if (hostile) {
|
||||
Statistics.enemiesSlain++;
|
||||
Badges.validateMonstersSlain();
|
||||
Statistics.qualifiedForNoKilling = false;
|
||||
|
||||
if (Dungeon.nightMode) {
|
||||
Statistics.nightHunt++;
|
||||
} else {
|
||||
Statistics.nightHunt = 0;
|
||||
}
|
||||
Badges.validateNightHunter();
|
||||
}
|
||||
|
||||
if (Dungeon.hero.lvl <= maxLvl && EXP > 0) {
|
||||
Dungeon.hero.sprite.showStatus( CharSprite.POSITIVE, TXT_EXP, EXP );
|
||||
Dungeon.hero.earnExp( EXP );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
super.die( cause );
|
||||
|
||||
if (Dungeon.hero.lvl <= maxLvl + 2) {
|
||||
dropLoot();
|
||||
}
|
||||
|
||||
if (Dungeon.hero.isAlive() && !Dungeon.visible[pos]) {
|
||||
GLog.i( TXT_DIED );
|
||||
}
|
||||
}
|
||||
|
||||
protected Object loot = null;
|
||||
protected float lootChance = 0;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void dropLoot() {
|
||||
if (loot != null && Random.Float() < lootChance) {
|
||||
Item item = null;
|
||||
if (loot instanceof Generator.Category) {
|
||||
|
||||
item = Generator.random( (Generator.Category)loot );
|
||||
|
||||
} else if (loot instanceof Class<?>) {
|
||||
|
||||
item = Generator.random( (Class<? extends Item>)loot );
|
||||
|
||||
} else {
|
||||
|
||||
item = (Item)loot;
|
||||
|
||||
}
|
||||
Dungeon.level.drop( item, pos ).sprite.drop();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean reset() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void beckon( int cell ) {
|
||||
|
||||
notice();
|
||||
|
||||
if (state != State.HUNTING) {
|
||||
state = State.WANDERING;
|
||||
}
|
||||
target = cell;
|
||||
}
|
||||
|
||||
public String description() {
|
||||
return "Real description is coming soon!";
|
||||
}
|
||||
|
||||
public void notice() {
|
||||
sprite.showAlert();
|
||||
}
|
||||
|
||||
public void yell( String str ) {
|
||||
GLog.n( "%s: \"%s\" ", name, str );
|
||||
}
|
||||
|
||||
public static abstract class NPC extends Mob {
|
||||
|
||||
{
|
||||
HP = HT = 1;
|
||||
EXP = 0;
|
||||
|
||||
hostile = false;
|
||||
state = State.PASSIVE;
|
||||
}
|
||||
|
||||
protected void throwItem() {
|
||||
Heap heap = Dungeon.level.heaps.get( pos );
|
||||
if (heap != null) {
|
||||
int n;
|
||||
do {
|
||||
n = pos + Level.NEIGHBOURS8[Random.Int( 8 )];
|
||||
} while (!Level.passable[n] && !Level.avoid[n]);
|
||||
Dungeon.level.drop( heap.pickUp(), n ).sprite.drop( pos );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beckon( int cell ) {
|
||||
}
|
||||
|
||||
abstract public void interact();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Amok;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Imp;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.KindOfWeapon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.Food;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Knuckles;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.MonkSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Monk extends Mob {
|
||||
|
||||
public static final String TXT_DISARM = "%s has knocked the %s from your hands!";
|
||||
|
||||
{
|
||||
name = "dwarf monk";
|
||||
spriteClass = MonkSprite.class;
|
||||
|
||||
HP = HT = 70;
|
||||
defenseSkill = 30;
|
||||
|
||||
EXP = 11;
|
||||
maxLvl = 21;
|
||||
|
||||
loot = new Food();
|
||||
lootChance = 0.083f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 12, 16 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float attackDelay() {
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "parried";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
Imp.Quest.process( this );
|
||||
|
||||
super.die( cause );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
|
||||
if (Random.Int( 6 ) == 0 && enemy == Dungeon.hero) {
|
||||
|
||||
Hero hero = Dungeon.hero;
|
||||
KindOfWeapon weapon = hero.belongings.weapon;
|
||||
|
||||
if (weapon != null && !(weapon instanceof Knuckles) && !weapon.cursed) {
|
||||
hero.belongings.weapon = null;
|
||||
Dungeon.level.drop( weapon, hero.pos ).sprite.drop();
|
||||
GLog.w( TXT_DISARM, name, weapon.name() );
|
||||
}
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"These monks are fanatics, who devoted themselves to protecting their city's secrets from all aliens. " +
|
||||
"They don't use any armor or weapons, relying solely on the art of hand-to-hand combat.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Amok.class );
|
||||
IMMUNITIES.add( Terror.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Statistics;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Frost;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.MysteryMeat;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.PiranhaSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Piranha extends Mob {
|
||||
|
||||
{
|
||||
name = "giant piranha";
|
||||
spriteClass = PiranhaSprite.class;
|
||||
|
||||
baseSpeed = 2f;
|
||||
|
||||
EXP = 0;
|
||||
}
|
||||
|
||||
public Piranha() {
|
||||
super();
|
||||
|
||||
HP = HT = 10 + Dungeon.depth * 5;
|
||||
defenseSkill = 10 + Dungeon.depth * 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
if (!Level.water[pos]) {
|
||||
die( null );
|
||||
return true;
|
||||
} else {
|
||||
return super.act();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( Dungeon.depth, 4 + Dungeon.depth * 2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 20 + Dungeon.depth * 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return Dungeon.depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
Dungeon.level.drop( new MysteryMeat(), pos ).sprite.drop();
|
||||
super.die( cause );
|
||||
|
||||
Statistics.piranhasKilled++;
|
||||
Badges.validatePiranhasKilled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getCloser( int target ) {
|
||||
|
||||
if (rooted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int step = Dungeon.findPath( this, pos, target,
|
||||
Level.water,
|
||||
Level.fieldOfView );
|
||||
if (step != -1) {
|
||||
move( step );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getFurther( int target ) {
|
||||
int step = Dungeon.flee( this, pos, target,
|
||||
Level.water,
|
||||
Level.fieldOfView );
|
||||
if (step != -1) {
|
||||
move( step );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"These carnivorous fish are not natural inhabitants of underground pools. " +
|
||||
"They were bred specifically to protect flooded treasure vaults.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Burning.class );
|
||||
IMMUNITIES.add( Paralysis.class );
|
||||
IMMUNITIES.add( ToxicGas.class );
|
||||
IMMUNITIES.add( Roots.class );
|
||||
IMMUNITIES.add( Frost.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Ghost;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.RatSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Rat extends Mob {
|
||||
|
||||
{
|
||||
name = "marsupial rat";
|
||||
spriteClass = RatSprite.class;
|
||||
|
||||
HP = HT = 8;
|
||||
defenseSkill = 3;
|
||||
|
||||
maxLvl = 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 1, 5 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
Ghost.Quest.process( pos );
|
||||
|
||||
super.die( cause );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Marsupial rats are aggressive, but rather weak denizens " +
|
||||
"of the sewers. They can be dangerous only in big numbers.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Cripple;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.MysteryMeat;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Leech;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ScorpioSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Scorpio extends Mob {
|
||||
|
||||
{
|
||||
name = "scorpio";
|
||||
spriteClass = ScorpioSprite.class;
|
||||
|
||||
HP = HT = 95;
|
||||
defenseSkill = 24;
|
||||
viewDistance = Light.DISTANCE;
|
||||
|
||||
EXP = 14;
|
||||
maxLvl = 25;
|
||||
|
||||
loot = new PotionOfHealing();
|
||||
lootChance = 0.125f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 20, 32 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 36;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return !Level.adjacent( pos, enemy.pos ) && Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( 2 ) == 0) {
|
||||
Buff.prolong( enemy, Cripple.class, Cripple.DURATION );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getCloser( int target ) {
|
||||
if (state == State.HUNTING) {
|
||||
return enemySeen && getFurther( target );
|
||||
} else {
|
||||
return super.getCloser( target );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropLoot() {
|
||||
if (Random.Int( 8 ) == 0) {
|
||||
Dungeon.level.drop( new PotionOfHealing(), pos ).sprite.drop();
|
||||
} else if (Random.Int( 6 ) == 0) {
|
||||
Dungeon.level.drop( new MysteryMeat(), pos ).sprite.drop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"These huge arachnid-like demonic creatures avoid close combat by all means, " +
|
||||
"firing crippling serrated spikes from long distances.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( Leech.class );
|
||||
RESISTANCES.add( Poison.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.SeniorSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Senior extends Monk {
|
||||
|
||||
{
|
||||
name = "senior monk";
|
||||
spriteClass = SeniorSprite.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 12, 20 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( 10 ) == 0) {
|
||||
Buff.prolong( enemy, Paralysis.class, 1.1f );
|
||||
}
|
||||
return super.attackProc( enemy, damage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
Badges.validateRare( this );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.Camera;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.SparkParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.LightningTrap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ShamanSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.watabou.utils.Callback;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Shaman extends Mob implements Callback {
|
||||
|
||||
private static final float TIME_TO_ZAP = 2f;
|
||||
|
||||
private static final String TXT_LIGHTNING_KILLED = "%s's lightning bolt killed you...";
|
||||
|
||||
{
|
||||
name = "gnoll shaman";
|
||||
spriteClass = ShamanSprite.class;
|
||||
|
||||
HP = HT = 18;
|
||||
defenseSkill = 8;
|
||||
|
||||
EXP = 6;
|
||||
maxLvl = 14;
|
||||
|
||||
loot = Generator.Category.SCROLL;
|
||||
lootChance = 0.33f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 2, 6 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 11;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
|
||||
if (Level.distance( pos, enemy.pos ) <= 1) {
|
||||
|
||||
return super.doAttack( enemy );
|
||||
|
||||
} else {
|
||||
|
||||
boolean visible = Level.fieldOfView[pos] || Level.fieldOfView[enemy.pos];
|
||||
if (visible) {
|
||||
((ShamanSprite)sprite).zap( enemy.pos );
|
||||
}
|
||||
|
||||
spend( TIME_TO_ZAP );
|
||||
|
||||
if (hit( this, enemy, true )) {
|
||||
int dmg = Random.Int( 2, 12 );
|
||||
if (Level.water[enemy.pos] && !enemy.flying) {
|
||||
dmg *= 1.5f;
|
||||
}
|
||||
enemy.damage( dmg, LightningTrap.LIGHTNING );
|
||||
|
||||
enemy.sprite.centerEmitter().burst( SparkParticle.FACTORY, 3 );
|
||||
enemy.sprite.flash();
|
||||
|
||||
if (enemy == Dungeon.hero) {
|
||||
|
||||
Camera.main.shake( 2, 0.3f );
|
||||
|
||||
if (!enemy.isAlive()) {
|
||||
Dungeon.fail( Utils.format( ResultDescriptions.MOB,
|
||||
Utils.indefinite( name ), Dungeon.depth ) );
|
||||
GLog.n( TXT_LIGHTNING_KILLED, name );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
enemy.sprite.showStatus( CharSprite.NEUTRAL, enemy.defenseVerb() );
|
||||
}
|
||||
|
||||
return !visible;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call() {
|
||||
next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"The most intelligent gnolls can master shamanistic magic. Gnoll shamans prefer " +
|
||||
"battle spells to compensate for lack of might, not hesitating to use them " +
|
||||
"on those who question their status in a tribe.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( LightningTrap.Electricity.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ShieldedSprite;
|
||||
|
||||
public class Shielded extends Brute {
|
||||
|
||||
{
|
||||
name = "shielded brute";
|
||||
spriteClass = ShieldedSprite.class;
|
||||
|
||||
defenseSkill = 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "blocked";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
Badges.validateRare( this );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.SkeletonSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Skeleton extends Mob {
|
||||
|
||||
private static final String TXT_HERO_KILLED = "You were killed by the explosion of bones...";
|
||||
|
||||
{
|
||||
name = "skeleton";
|
||||
spriteClass = SkeletonSprite.class;
|
||||
|
||||
HP = HT = 25;
|
||||
defenseSkill = 9;
|
||||
|
||||
EXP = 5;
|
||||
maxLvl = 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 3, 8 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
super.die( cause );
|
||||
|
||||
boolean heroKilled = false;
|
||||
for (int i=0; i < Level.NEIGHBOURS8.length; i++) {
|
||||
Char ch = findChar( pos + Level.NEIGHBOURS8[i] );
|
||||
if (ch != null && ch.isAlive()) {
|
||||
int damage = Math.max( 0, damageRoll() - Random.IntRange( 0, ch.dr() / 2 ) );
|
||||
ch.damage( damage, this );
|
||||
if (ch == Dungeon.hero && !ch.isAlive()) {
|
||||
heroKilled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Dungeon.visible[pos]) {
|
||||
Sample.INSTANCE.play( Assets.SND_BONES );
|
||||
}
|
||||
|
||||
if (heroKilled) {
|
||||
Dungeon.fail( Utils.format( ResultDescriptions.MOB, Utils.indefinite( name ), Dungeon.depth ) );
|
||||
GLog.n( TXT_HERO_KILLED );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropLoot() {
|
||||
if (Random.Int( 5 ) == 0) {
|
||||
Item loot = Generator.random( Generator.Category.WEAPON );
|
||||
for (int i=0; i < 2; i++) {
|
||||
Item l = Generator.random( Generator.Category.WEAPON );
|
||||
if (l.level < loot.level) {
|
||||
loot = l;
|
||||
}
|
||||
}
|
||||
Dungeon.level.drop( loot, pos ).sprite.drop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "blocked";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Skeletons are composed of corpses bones from unlucky adventurers and inhabitants of the dungeon, " +
|
||||
"animated by emanations of evil magic from the depths below. After they have been " +
|
||||
"damaged enough, they disintegrate in an explosion of bones.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Death.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Web;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.MysteryMeat;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.SpinnerSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Spinner extends Mob {
|
||||
|
||||
{
|
||||
name = "cave spinner";
|
||||
spriteClass = SpinnerSprite.class;
|
||||
|
||||
HP = HT = 50;
|
||||
defenseSkill = 14;
|
||||
|
||||
EXP = 9;
|
||||
maxLvl = 16;
|
||||
|
||||
loot = new MysteryMeat();
|
||||
lootChance = 0.125f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 12, 16 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void nowhereToRun() {
|
||||
if (buff( Terror.class ) == null) {
|
||||
state = State.HUNTING;
|
||||
} else {
|
||||
super.nowhereToRun();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
boolean result = super.act();
|
||||
|
||||
if (state == State.FLEEING && buff( Terror.class ) == null &&
|
||||
enemySeen && enemy.buff( Poison.class ) == null) {
|
||||
|
||||
state = State.HUNTING;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( 2 ) == 0) {
|
||||
Buff.affect( enemy, Poison.class ).set( Random.Int( 5, 7 ) * Poison.durationFactor( enemy ) );
|
||||
state = State.FLEEING;
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void move( int step ) {
|
||||
if (state == State.FLEEING) {
|
||||
GameScene.add( Blob.seed( pos, Random.Int( 5, 7 ), Web.class ) );
|
||||
}
|
||||
super.move( step );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"These greenish furry cave spiders try to avoid direct combat, preferring to wait in the distance " +
|
||||
"while their victim, entangled in the spinner's excreted cobweb, slowly dies from their poisonous bite.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( Poison.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Roots.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Journal;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon.Enchantment;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Leech;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.MeleeWeapon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.StatueSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Statue extends Mob {
|
||||
|
||||
{
|
||||
name = "animated statue";
|
||||
spriteClass = StatueSprite.class;
|
||||
|
||||
EXP = 0;
|
||||
state = State.PASSIVE;
|
||||
}
|
||||
|
||||
private Weapon weapon;
|
||||
|
||||
public Statue() {
|
||||
super();
|
||||
|
||||
do {
|
||||
weapon = (Weapon)Generator.random( Generator.Category.WEAPON );
|
||||
} while (!(weapon instanceof MeleeWeapon) || weapon.level < 0);
|
||||
|
||||
weapon.identify();
|
||||
weapon.enchant( Enchantment.random() );
|
||||
|
||||
HP = HT = 15 + Dungeon.depth * 5;
|
||||
defenseSkill = 4 + Dungeon.depth;
|
||||
}
|
||||
|
||||
private static final String WEAPON = "weapon";
|
||||
|
||||
@Override
|
||||
public void storeInBundle( Bundle bundle ) {
|
||||
super.storeInBundle( bundle );
|
||||
bundle.put( WEAPON, weapon );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
super.restoreFromBundle( bundle );
|
||||
weapon = (Weapon)bundle.get( WEAPON );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
if (Dungeon.visible[pos]) {
|
||||
Journal.add( Journal.Feature.STATUE );
|
||||
}
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( weapon.MIN, weapon.MAX );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return (int)((9 + Dungeon.depth) * weapon.ACU);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float attackDelay() {
|
||||
return weapon.DLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return Dungeon.depth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
|
||||
if (state == State.PASSIVE) {
|
||||
state = State.HUNTING;
|
||||
}
|
||||
|
||||
super.damage( dmg, src );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
weapon.proc( this, enemy, damage );
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beckon( int cell ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
Dungeon.level.drop( weapon, pos ).sprite.drop();
|
||||
super.die( cause );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
Journal.remove( Journal.Feature.STATUE );
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
state = State.PASSIVE;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"You would think that it's just another ugly statue of this dungeon, but its red glowing eyes give itself away. " +
|
||||
"While the statue itself is made of stone, the _" + weapon.name() + "_, it's wielding, looks real.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( ToxicGas.class );
|
||||
RESISTANCES.add( Poison.class );
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
IMMUNITIES.add( Leech.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Charm;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Light;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfLullaby;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlink;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Leech;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.SuccubusSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Succubus extends Mob {
|
||||
|
||||
private static final int BLINK_DELAY = 5;
|
||||
|
||||
private int delay = 0;
|
||||
|
||||
{
|
||||
name = "succubus";
|
||||
spriteClass = SuccubusSprite.class;
|
||||
|
||||
HP = HT = 80;
|
||||
defenseSkill = 25;
|
||||
viewDistance = Light.DISTANCE;
|
||||
|
||||
EXP = 12;
|
||||
maxLvl = 25;
|
||||
|
||||
loot = new ScrollOfLullaby();
|
||||
lootChance = 0.05f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 15, 25 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
|
||||
if (Random.Int( 3 ) == 0) {
|
||||
Buff.affect( enemy, Charm.class, Charm.durationFactor( enemy ) * Random.IntRange( 2, 5 ) );
|
||||
enemy.sprite.centerEmitter().start( Speck.factory( Speck.HEART ), 0.2f, 5 );
|
||||
Sample.INSTANCE.play( Assets.SND_CHARMS );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getCloser( int target ) {
|
||||
if (Level.fieldOfView[target] && Level.distance( pos, target ) > 2 && delay <= 0) {
|
||||
|
||||
blink( target );
|
||||
spend( -1 / speed() );
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
delay--;
|
||||
return super.getCloser( target );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void blink( int target ) {
|
||||
|
||||
int cell = Ballistica.cast( pos, target, true, true );
|
||||
|
||||
if (Actor.findChar( cell ) != null && Ballistica.distance > 1) {
|
||||
cell = Ballistica.trace[Ballistica.distance - 2];
|
||||
}
|
||||
|
||||
WandOfBlink.appear( this, cell );
|
||||
|
||||
delay = BLINK_DELAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 40;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"The succubi are demons that look like seductive (in a slightly gothic way) girls. Using its magic, the succubus " +
|
||||
"can charm a hero, who will become unable to attack anything until the charm wears off.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( Leech.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Sleep.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.ArrayList;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Door;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.SwarmSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Swarm extends Mob {
|
||||
|
||||
{
|
||||
name = "swarm of flies";
|
||||
spriteClass = SwarmSprite.class;
|
||||
|
||||
HP = HT = 80;
|
||||
defenseSkill = 5;
|
||||
|
||||
maxLvl = 10;
|
||||
|
||||
flying = true;
|
||||
}
|
||||
|
||||
private static final float SPLIT_DELAY = 1f;
|
||||
|
||||
int generation = 0;
|
||||
|
||||
private static final String GENERATION = "generation";
|
||||
|
||||
@Override
|
||||
public void storeInBundle( Bundle bundle ) {
|
||||
super.storeInBundle( bundle );
|
||||
bundle.put( GENERATION, generation );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
super.restoreFromBundle( bundle );
|
||||
generation = bundle.getInt( GENERATION );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 1, 4 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc( Char enemy, int damage ) {
|
||||
|
||||
if (HP >= damage + 2) {
|
||||
ArrayList<Integer> candidates = new ArrayList<Integer>();
|
||||
boolean[] passable = Level.passable;
|
||||
|
||||
int[] neighbours = {pos + 1, pos - 1, pos + Level.WIDTH, pos - Level.WIDTH};
|
||||
for (int n : neighbours) {
|
||||
if (passable[n] && Actor.findChar( n ) == null) {
|
||||
candidates.add( n );
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.size() > 0) {
|
||||
|
||||
Swarm clone = split();
|
||||
clone.HP = (HP - damage) / 2;
|
||||
clone.pos = Random.element( candidates );
|
||||
clone.state = State.HUNTING;
|
||||
|
||||
if (Dungeon.level.map[clone.pos] == Terrain.DOOR) {
|
||||
Door.enter( clone.pos );
|
||||
}
|
||||
|
||||
GameScene.add( clone, SPLIT_DELAY );
|
||||
Actor.addDelayed( new Pushing( clone, pos, clone.pos ), -1 );
|
||||
|
||||
HP -= clone.HP;
|
||||
}
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "evaded";
|
||||
}
|
||||
|
||||
private Swarm split() {
|
||||
Swarm clone = new Swarm();
|
||||
clone.generation = generation + 1;
|
||||
if (buff( Burning.class ) != null) {
|
||||
Buff.affect( clone, Burning.class ).reignite( clone );
|
||||
}
|
||||
if (buff( Poison.class ) != null) {
|
||||
Buff.affect( clone, Poison.class ).set( 2 );
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dropLoot() {
|
||||
if (Random.Int( 5 * (generation + 1) ) == 0) {
|
||||
Dungeon.level.drop( new PotionOfHealing(), pos ).sprite.drop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"The deadly swarm of flies buzzes angrily. Every non-magical attack " +
|
||||
"will split it into two smaller but equally dangerous swarms.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges.Badge;
|
||||
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.Poison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.TomeOfMastery;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfMagicMapping;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.TenguSprite;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Tengu extends Mob {
|
||||
|
||||
private static final int JUMP_DELAY = 5;
|
||||
|
||||
{
|
||||
name = "Tengu";
|
||||
spriteClass = TenguSprite.class;
|
||||
|
||||
HP = HT = 120;
|
||||
EXP = 20;
|
||||
defenseSkill = 20;
|
||||
}
|
||||
|
||||
private int timeToJump = JUMP_DELAY;
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 8, 15 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
Badges.Badge badgeToCheck = null;
|
||||
switch (Dungeon.hero.heroClass) {
|
||||
case WARRIOR:
|
||||
badgeToCheck = Badge.MASTERY_WARRIOR;
|
||||
break;
|
||||
case MAGE:
|
||||
badgeToCheck = Badge.MASTERY_MAGE;
|
||||
break;
|
||||
case ROGUE:
|
||||
badgeToCheck = Badge.MASTERY_ROGUE;
|
||||
break;
|
||||
case HUNTRESS:
|
||||
badgeToCheck = Badge.MASTERY_HUNTRESS;
|
||||
break;
|
||||
}
|
||||
if (!Badges.isUnlocked( badgeToCheck )) {
|
||||
Dungeon.level.drop( new TomeOfMastery(), pos ).sprite.drop();
|
||||
}
|
||||
|
||||
GameScene.bossSlain();
|
||||
Dungeon.level.drop( new SkeletonKey( Dungeon.depth ), pos ).sprite.drop();
|
||||
super.die( cause );
|
||||
|
||||
Badges.validateBossSlain();
|
||||
|
||||
yell( "Free at last..." );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getCloser( int target ) {
|
||||
if (Level.fieldOfView[target]) {
|
||||
jump();
|
||||
return true;
|
||||
} else {
|
||||
return super.getCloser( target );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
timeToJump--;
|
||||
if (timeToJump <= 0 && Level.adjacent( pos, enemy.pos )) {
|
||||
jump();
|
||||
return true;
|
||||
} else {
|
||||
return super.doAttack( enemy );
|
||||
}
|
||||
}
|
||||
|
||||
private void jump() {
|
||||
timeToJump = JUMP_DELAY;
|
||||
|
||||
for (int i=0; i < 4; i++) {
|
||||
int trapPos;
|
||||
do {
|
||||
trapPos = Random.Int( Level.LENGTH );
|
||||
} while (!Level.fieldOfView[trapPos] || !Level.passable[trapPos]);
|
||||
|
||||
if (Dungeon.level.map[trapPos] == Terrain.INACTIVE_TRAP) {
|
||||
Level.set( trapPos, Terrain.POISON_TRAP );
|
||||
GameScene.updateMap( trapPos );
|
||||
ScrollOfMagicMapping.discover( trapPos );
|
||||
}
|
||||
}
|
||||
|
||||
int newPos;
|
||||
do {
|
||||
newPos = Random.Int( Level.LENGTH );
|
||||
} while (
|
||||
!Level.fieldOfView[newPos] ||
|
||||
!Level.passable[newPos] ||
|
||||
Level.adjacent( newPos, enemy.pos ) ||
|
||||
Actor.findChar( newPos ) != null);
|
||||
|
||||
sprite.move( pos, newPos );
|
||||
move( newPos );
|
||||
|
||||
if (Dungeon.visible[newPos]) {
|
||||
CellEmitter.get( newPos ).burst( Speck.factory( Speck.WOOL ), 6 );
|
||||
Sample.INSTANCE.play( Assets.SND_PUFF );
|
||||
}
|
||||
|
||||
spend( 1 / speed() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notice() {
|
||||
super.notice();
|
||||
yell( "Gotcha, " + Dungeon.hero.heroClass.title() + "!" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Tengu are members of the ancient assassins clan, which is also called Tengu. " +
|
||||
"These assassins are noted for extensive use of shuriken and traps.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( ToxicGas.class );
|
||||
RESISTANCES.add( Poison.class );
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfHaggler;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ThiefSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Thief extends Mob {
|
||||
|
||||
protected static final String TXT_STOLE = "%s stole %s from you!";
|
||||
protected static final String TXT_CARRIES = "\n\n%s is carrying a _%s_. Stolen obviously.";
|
||||
|
||||
public Item item;
|
||||
|
||||
{
|
||||
name = "crazy thief";
|
||||
spriteClass = ThiefSprite.class;
|
||||
|
||||
HP = HT = 20;
|
||||
defenseSkill = 12;
|
||||
|
||||
EXP = 5;
|
||||
maxLvl = 10;
|
||||
|
||||
loot = RingOfHaggler.class;
|
||||
lootChance = 0.01f;
|
||||
}
|
||||
|
||||
private static final String ITEM = "item";
|
||||
|
||||
@Override
|
||||
public void storeInBundle( Bundle bundle ) {
|
||||
super.storeInBundle( bundle );
|
||||
bundle.put( ITEM, item );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
super.restoreFromBundle( bundle );
|
||||
item = (Item)bundle.get( ITEM );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 1, 7 );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float attackDelay() {
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void nowhereToRun() {
|
||||
if (buff( Terror.class ) == null) {
|
||||
sprite.showStatus( CharSprite.NEGATIVE, TXT_RAGE );
|
||||
state = State.HUNTING;
|
||||
} else {
|
||||
super.nowhereToRun();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
|
||||
super.die( cause );
|
||||
|
||||
if (item != null) {
|
||||
Dungeon.level.drop( item, pos ).sprite.drop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (item == null && enemy instanceof Hero && steal( (Hero)enemy )) {
|
||||
state = State.FLEEING;
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc(Char enemy, int damage) {
|
||||
if (state == State.FLEEING) {
|
||||
Dungeon.level.drop( new Gold(), pos ).sprite.drop();
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
protected boolean steal( Hero hero ) {
|
||||
|
||||
Item item = hero.belongings.randomUnequipped();
|
||||
if (item != null) {
|
||||
|
||||
GLog.w( TXT_STOLE, this.name, item.name() );
|
||||
|
||||
item.detachAll( hero.belongings.backpack );
|
||||
this.item = item;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
String desc =
|
||||
"Deeper levels of the dungeon have always been a hiding place for all kinds of criminals. " +
|
||||
"Not all of them could keep a clear mind during their extended periods so far from daylight. Long ago, " +
|
||||
"these crazy thieves and bandits have forgotten who they are and why they steal.";
|
||||
|
||||
if (item != null) {
|
||||
desc += String.format( TXT_CARRIES, Utils.capitalize( this.name ), item.name() );
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Weakness;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.WarlockSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.watabou.utils.Callback;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Warlock extends Mob implements Callback {
|
||||
|
||||
private static final float TIME_TO_ZAP = 1f;
|
||||
|
||||
private static final String TXT_SHADOWBOLT_KILLED = "%s's shadow bolt killed you...";
|
||||
|
||||
{
|
||||
name = "dwarf warlock";
|
||||
spriteClass = WarlockSprite.class;
|
||||
|
||||
HP = HT = 70;
|
||||
defenseSkill = 18;
|
||||
|
||||
EXP = 11;
|
||||
maxLvl = 21;
|
||||
|
||||
loot = Generator.Category.POTION;
|
||||
lootChance = 0.83f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 12, 20 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 25;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos;
|
||||
}
|
||||
|
||||
protected boolean doAttack( Char enemy ) {
|
||||
|
||||
if (Level.adjacent( pos, enemy.pos )) {
|
||||
|
||||
return super.doAttack( enemy );
|
||||
|
||||
} else {
|
||||
|
||||
boolean visible = Level.fieldOfView[pos] || Level.fieldOfView[enemy.pos];
|
||||
if (visible) {
|
||||
((WarlockSprite)sprite).zap( enemy.pos );
|
||||
} else {
|
||||
zap();
|
||||
}
|
||||
|
||||
return !visible;
|
||||
}
|
||||
}
|
||||
|
||||
private void zap() {
|
||||
spend( TIME_TO_ZAP );
|
||||
|
||||
if (hit( this, enemy, true )) {
|
||||
if (enemy == Dungeon.hero && Random.Int( 2 ) == 0) {
|
||||
Buff.prolong( enemy, Weakness.class, Weakness.duration( enemy ) );
|
||||
}
|
||||
|
||||
int dmg = Random.Int( 12, 18 );
|
||||
enemy.damage( dmg, this );
|
||||
|
||||
if (!enemy.isAlive() && enemy == Dungeon.hero) {
|
||||
Dungeon.fail( Utils.format( ResultDescriptions.MOB,
|
||||
Utils.indefinite( name ), Dungeon.depth ) );
|
||||
GLog.n( TXT_SHADOWBOLT_KILLED, name );
|
||||
}
|
||||
} else {
|
||||
enemy.sprite.showStatus( CharSprite.NEUTRAL, enemy.defenseVerb() );
|
||||
}
|
||||
}
|
||||
|
||||
public void onZapComplete() {
|
||||
zap();
|
||||
next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call() {
|
||||
next();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"When dwarves' interests have shifted from engineering to arcane arts, " +
|
||||
"warlocks have come to power in the city. They started with elemental magic, " +
|
||||
"but soon switched to demonology and necromancy.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( Death.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.tweeners.AlphaTweener;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.WraithSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Wraith extends Mob {
|
||||
|
||||
private static final float SPAWN_DELAY = 2f;
|
||||
|
||||
private int level;
|
||||
|
||||
{
|
||||
name = "wraith";
|
||||
spriteClass = WraithSprite.class;
|
||||
|
||||
HP = HT = 1;
|
||||
EXP = 0;
|
||||
|
||||
flying = true;
|
||||
}
|
||||
|
||||
private static final String LEVEL = "level";
|
||||
|
||||
@Override
|
||||
public void storeInBundle( Bundle bundle ) {
|
||||
super.storeInBundle( bundle );
|
||||
bundle.put( LEVEL, level );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
super.restoreFromBundle( bundle );
|
||||
level = bundle.getInt( LEVEL );
|
||||
adjustStats( level );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 1, 3 + level );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 10 + level;
|
||||
}
|
||||
|
||||
public void adjustStats( int level ) {
|
||||
this.level = level;
|
||||
defenseSkill = attackSkill( null ) * 5;
|
||||
enemySeen = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "evaded";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
state = State.WANDERING;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"A wraith is a vengeful spirit of a sinner, whose grave or tomb was disturbed. " +
|
||||
"Being an ethereal entity, it is very hard to hit with a regular weapon.";
|
||||
}
|
||||
|
||||
public static void spawnAround( int pos ) {
|
||||
for (int n : Level.NEIGHBOURS4) {
|
||||
int cell = pos + n;
|
||||
if (Level.passable[cell] && Actor.findChar( cell ) == null) {
|
||||
spawnAt( cell );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Wraith spawnAt( int pos ) {
|
||||
if (Level.passable[pos] && Actor.findChar( pos ) == null) {
|
||||
|
||||
Wraith w = new Wraith();
|
||||
w.adjustStats( Dungeon.depth );
|
||||
w.pos = pos;
|
||||
w.state = State.HUNTING;
|
||||
GameScene.add( w, SPAWN_DELAY );
|
||||
|
||||
w.sprite.alpha( 0 );
|
||||
w.sprite.parent.add( new AlphaTweener( w.sprite, 1, 0.5f ) );
|
||||
|
||||
w.sprite.emitter().burst( ShadowParticle.CURSE, 5 );
|
||||
|
||||
return w;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Death.class );
|
||||
IMMUNITIES.add( Terror.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,430 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.ResultDescriptions;
|
||||
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.Amok;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Burning;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Charm;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Ooze;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Sleep;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Terror;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.keys.SkeletonKey;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfPsionicBlast;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.enchantments.Death;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.BurningFistSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.LarvaSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.RottingFistSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.YogSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Yog extends Mob {
|
||||
|
||||
{
|
||||
name = "Yog-Dzewa";
|
||||
spriteClass = YogSprite.class;
|
||||
|
||||
HP = HT = 300;
|
||||
|
||||
EXP = 50;
|
||||
|
||||
state = State.PASSIVE;
|
||||
}
|
||||
|
||||
private static final String TXT_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.";
|
||||
|
||||
private static int fistsCount = 0;
|
||||
|
||||
public Yog() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void spawnFists() {
|
||||
RottingFist fist1 = new RottingFist();
|
||||
BurningFist fist2 = new BurningFist();
|
||||
|
||||
do {
|
||||
fist1.pos = pos + Level.NEIGHBOURS8[Random.Int( 8 )];
|
||||
fist2.pos = pos + Level.NEIGHBOURS8[Random.Int( 8 )];
|
||||
} while (!Level.passable[fist1.pos] || !Level.passable[fist2.pos] || fist1.pos == fist2.pos);
|
||||
|
||||
GameScene.add( fist1 );
|
||||
GameScene.add( fist2 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
|
||||
if (fistsCount > 0) {
|
||||
|
||||
for (Mob mob : Dungeon.level.mobs) {
|
||||
if (mob instanceof BurningFist || mob instanceof RottingFist) {
|
||||
mob.beckon( pos );
|
||||
}
|
||||
}
|
||||
|
||||
dmg >>= fistsCount;
|
||||
}
|
||||
|
||||
super.damage( dmg, src );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc( Char enemy, int damage ) {
|
||||
|
||||
ArrayList<Integer> spawnPoints = new ArrayList<Integer>();
|
||||
|
||||
for (int i=0; i < Level.NEIGHBOURS8.length; i++) {
|
||||
int p = pos + Level.NEIGHBOURS8[i];
|
||||
if (Actor.findChar( p ) == null && (Level.passable[p] || Level.avoid[p])) {
|
||||
spawnPoints.add( p );
|
||||
}
|
||||
}
|
||||
|
||||
if (spawnPoints.size() > 0) {
|
||||
Larva larva = new Larva();
|
||||
larva.pos = Random.element( spawnPoints );
|
||||
|
||||
GameScene.add( larva );
|
||||
Actor.addDelayed( new Pushing( larva, pos, larva.pos ), -1 );
|
||||
}
|
||||
|
||||
return super.defenseProc(enemy, damage);
|
||||
}
|
||||
|
||||
@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 BurningFist || mob instanceof RottingFist) {
|
||||
mob.die( cause );
|
||||
}
|
||||
}
|
||||
|
||||
GameScene.bossSlain();
|
||||
Dungeon.level.drop( new SkeletonKey( Dungeon.depth ), pos ).sprite.drop();
|
||||
super.die( cause );
|
||||
|
||||
yell( "..." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notice() {
|
||||
super.notice();
|
||||
yell( "Hope is an illusion..." );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return TXT_DESC;
|
||||
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
|
||||
IMMUNITIES.add( Death.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( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
|
||||
public static class RottingFist extends Mob {
|
||||
|
||||
private static final int REGENERATION = 4;
|
||||
|
||||
{
|
||||
name = "rotting fist";
|
||||
spriteClass = RottingFistSprite.class;
|
||||
|
||||
HP = HT = 300;
|
||||
defenseSkill = 25;
|
||||
|
||||
EXP = 0;
|
||||
|
||||
state = State.WANDERING;
|
||||
}
|
||||
|
||||
public RottingFist() {
|
||||
super();
|
||||
fistsCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
fistsCount--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 36;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 24, 36 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
if (Random.Int( 3 ) == 0) {
|
||||
Buff.affect( enemy, Ooze.class );
|
||||
enemy.sprite.burst( 0xFF000000, 5 );
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean act() {
|
||||
|
||||
if (Level.water[pos] && HP < HT) {
|
||||
sprite.emitter().burst( ShadowParticle.UP, 2 );
|
||||
HP += REGENERATION;
|
||||
}
|
||||
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return TXT_DESC;
|
||||
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( ToxicGas.class );
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Amok.class );
|
||||
IMMUNITIES.add( Sleep.class );
|
||||
IMMUNITIES.add( Terror.class );
|
||||
IMMUNITIES.add( Poison.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BurningFist extends Mob {
|
||||
|
||||
{
|
||||
name = "burning fist";
|
||||
spriteClass = BurningFistSprite.class;
|
||||
|
||||
HP = HT = 200;
|
||||
defenseSkill = 25;
|
||||
|
||||
EXP = 0;
|
||||
|
||||
state = State.WANDERING;
|
||||
}
|
||||
|
||||
public BurningFist() {
|
||||
super();
|
||||
fistsCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
fistsCount--;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 36;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 20, 32 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 15;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAttack( Char enemy ) {
|
||||
return Ballistica.cast( pos, enemy.pos, false, true ) == enemy.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean attack( Char enemy ) {
|
||||
|
||||
if (!Level.adjacent( pos, enemy.pos )) {
|
||||
spend( attackDelay() );
|
||||
|
||||
if (hit( this, enemy, true )) {
|
||||
|
||||
int dmg = damageRoll();
|
||||
enemy.damage( dmg, this );
|
||||
|
||||
enemy.sprite.bloodBurstA( sprite.center(), dmg );
|
||||
enemy.sprite.flash();
|
||||
|
||||
if (!enemy.isAlive() && enemy == Dungeon.hero) {
|
||||
Dungeon.fail( Utils.format( ResultDescriptions.BOSS, name, Dungeon.depth ) );
|
||||
GLog.n( TXT_KILL, name );
|
||||
}
|
||||
return true;
|
||||
|
||||
} else {
|
||||
|
||||
enemy.sprite.showStatus( CharSprite.NEUTRAL, enemy.defenseVerb() );
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return super.attack( enemy );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean act() {
|
||||
|
||||
for (int i=0; i < Level.NEIGHBOURS9.length; i++) {
|
||||
GameScene.add( Blob.seed( pos + Level.NEIGHBOURS9[i], 2, Fire.class ) );
|
||||
}
|
||||
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return TXT_DESC;
|
||||
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> RESISTANCES = new HashSet<Class<?>>();
|
||||
static {
|
||||
RESISTANCES.add( ToxicGas.class );
|
||||
RESISTANCES.add( Death.class );
|
||||
RESISTANCES.add( ScrollOfPsionicBlast.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> resistances() {
|
||||
return RESISTANCES;
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Amok.class );
|
||||
IMMUNITIES.add( Sleep.class );
|
||||
IMMUNITIES.add( Terror.class );
|
||||
IMMUNITIES.add( Burning.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Larva extends Mob {
|
||||
|
||||
{
|
||||
name = "god's larva";
|
||||
spriteClass = LarvaSprite.class;
|
||||
|
||||
HP = HT = 25;
|
||||
defenseSkill = 20;
|
||||
|
||||
EXP = 0;
|
||||
|
||||
state = State.HUNTING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 15, 20 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return TXT_DESC;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Badges;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Journal;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.EquipableItem;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.quest.DarkGold;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.quest.Pickaxe;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfUpgrade;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Room.Type;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.BlacksmithSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBlacksmith;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndQuest;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Blacksmith extends Mob.NPC {
|
||||
|
||||
private static final String TXT_GOLD_1 =
|
||||
"Hey human! Wanna be useful, eh? Take dis pickaxe and mine me some _dark gold ore_, _15 pieces_ should be enough. " +
|
||||
"What do you mean, how am I gonna pay? You greedy...\n" +
|
||||
"Ok, ok, I don't have money to pay, but I can do some smithin' for you. Consider yourself lucky, " +
|
||||
"I'm the only blacksmith around.";
|
||||
private static final String TXT_BLOOD_1 =
|
||||
"Hey human! Wanna be useful, eh? Take dis pickaxe and _kill a bat_ wit' it, I need its blood on the head. " +
|
||||
"What do you mean, how am I gonna pay? You greedy...\n" +
|
||||
"Ok, ok, I don't have money to pay, but I can do some smithin' for you. Consider yourself lucky, " +
|
||||
"I'm the only blacksmith around.";
|
||||
private static final String TXT2 =
|
||||
"Are you kiddin' me? Where is my pickaxe?!";
|
||||
private static final String TXT3 =
|
||||
"Dark gold ore. 15 pieces. Seriously, is it dat hard?";
|
||||
private static final String TXT4 =
|
||||
"I said I need bat blood on the pickaxe. Chop chop!";
|
||||
private static final String TXT_COMPLETED =
|
||||
"Oh, you have returned... Better late dan never.";
|
||||
private static final String TXT_GET_LOST =
|
||||
"I'm busy. Get lost!";
|
||||
|
||||
private static final String TXT_LOOKS_BETTER = "your %s certainly looks better now";
|
||||
|
||||
{
|
||||
name = "troll blacksmith";
|
||||
spriteClass = BlacksmithSprite.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
throwItem();
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact() {
|
||||
|
||||
sprite.turnTo( pos, Dungeon.hero.pos );
|
||||
|
||||
if (!Quest.given) {
|
||||
|
||||
GameScene.show( new WndQuest( this,
|
||||
Quest.alternative ? TXT_BLOOD_1 : TXT_GOLD_1 ) {
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
|
||||
Quest.given = true;
|
||||
Quest.completed = false;
|
||||
|
||||
Pickaxe pick = new Pickaxe();
|
||||
if (pick.doPickUp( Dungeon.hero )) {
|
||||
GLog.i( Hero.TXT_YOU_NOW_HAVE, pick.name() );
|
||||
} else {
|
||||
Dungeon.level.drop( pick, Dungeon.hero.pos ).sprite.drop();
|
||||
}
|
||||
};
|
||||
} );
|
||||
|
||||
Journal.add( Journal.Feature.TROLL );
|
||||
|
||||
} else if (!Quest.completed) {
|
||||
if (Quest.alternative) {
|
||||
|
||||
Pickaxe pick = Dungeon.hero.belongings.getItem( Pickaxe.class );
|
||||
if (pick == null) {
|
||||
tell( TXT2 );
|
||||
} else if (!pick.bloodStained) {
|
||||
tell( TXT4 );
|
||||
} else {
|
||||
if (pick.isEquipped( Dungeon.hero )) {
|
||||
pick.doUnequip( Dungeon.hero, false );
|
||||
}
|
||||
pick.detach( Dungeon.hero.belongings.backpack );
|
||||
tell( TXT_COMPLETED );
|
||||
|
||||
Quest.completed = true;
|
||||
Quest.reforged = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
Pickaxe pick = Dungeon.hero.belongings.getItem( Pickaxe.class );
|
||||
DarkGold gold = Dungeon.hero.belongings.getItem( DarkGold.class );
|
||||
if (pick == null) {
|
||||
tell( TXT2 );
|
||||
} else if (gold == null || gold.quantity() < 15) {
|
||||
tell( TXT3 );
|
||||
} else {
|
||||
if (pick.isEquipped( Dungeon.hero )) {
|
||||
pick.doUnequip( Dungeon.hero, false );
|
||||
}
|
||||
pick.detach( Dungeon.hero.belongings.backpack );
|
||||
gold.detachAll( Dungeon.hero.belongings.backpack );
|
||||
tell( TXT_COMPLETED );
|
||||
|
||||
Quest.completed = true;
|
||||
Quest.reforged = false;
|
||||
}
|
||||
|
||||
}
|
||||
} else if (!Quest.reforged) {
|
||||
|
||||
GameScene.show( new WndBlacksmith( this, Dungeon.hero ) );
|
||||
|
||||
} else {
|
||||
|
||||
tell( TXT_GET_LOST );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void tell( String text ) {
|
||||
GameScene.show( new WndQuest( this, text ) );
|
||||
}
|
||||
|
||||
public static String verify( Item item1, Item item2 ) {
|
||||
|
||||
if (item1 == item2) {
|
||||
return "Select 2 different items, not the same item twice!";
|
||||
}
|
||||
|
||||
if (!item1.isSimilar( item2 )) {
|
||||
return "Select 2 items of the same type!";
|
||||
}
|
||||
|
||||
if (!item1.isIdentified() || !item2.isIdentified()) {
|
||||
return "I need to know what I'm working with, identify them first!";
|
||||
}
|
||||
|
||||
if (item1.cursed || item2.cursed) {
|
||||
return "I don't work with cursed items!";
|
||||
}
|
||||
|
||||
if (item1.level < 0 || item2.level < 0) {
|
||||
return "It's a junk, the quality is too poor!";
|
||||
}
|
||||
|
||||
if (!item1.isUpgradable() || !item2.isUpgradable()) {
|
||||
return "I can't reforge these items!";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void upgrade( Item item1, Item item2 ) {
|
||||
|
||||
Item first, second;
|
||||
if (item2.level > item1.level) {
|
||||
first = item2;
|
||||
second = item1;
|
||||
} else {
|
||||
first = item1;
|
||||
second = item2;
|
||||
}
|
||||
|
||||
Sample.INSTANCE.play( Assets.SND_EVOKE );
|
||||
ScrollOfUpgrade.upgrade( Dungeon.hero );
|
||||
Item.evoke( Dungeon.hero );
|
||||
|
||||
if (first.isEquipped( Dungeon.hero )) {
|
||||
((EquipableItem)first).doUnequip( Dungeon.hero, true );
|
||||
}
|
||||
first.upgrade();
|
||||
GLog.p( TXT_LOOKS_BETTER, first.name() );
|
||||
Dungeon.hero.spendAndNext( 2f );
|
||||
Badges.validateItemLevelAquired( first );
|
||||
|
||||
if (second.isEquipped( Dungeon.hero )) {
|
||||
((EquipableItem)second).doUnequip( Dungeon.hero, false );
|
||||
}
|
||||
second.detachAll( Dungeon.hero.belongings.backpack );
|
||||
|
||||
Quest.reforged = true;
|
||||
|
||||
Journal.remove( Journal.Feature.TROLL );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseSkill( Char enemy ) {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"This troll blacksmith looks like all trolls look: he is tall and lean, and his skin resembles stone " +
|
||||
"in both color and texture. The troll blacksmith is tinkering with unproportionally small tools.";
|
||||
}
|
||||
|
||||
public static class Quest {
|
||||
|
||||
private static boolean spawned;
|
||||
|
||||
private static boolean alternative;
|
||||
private static boolean given;
|
||||
private static boolean completed;
|
||||
private static boolean reforged;
|
||||
|
||||
public static void reset() {
|
||||
spawned = false;
|
||||
given = false;
|
||||
completed = false;
|
||||
reforged = false;
|
||||
}
|
||||
|
||||
private static final String NODE = "blacksmith";
|
||||
|
||||
private static final String SPAWNED = "spawned";
|
||||
private static final String ALTERNATIVE = "alternative";
|
||||
private static final String GIVEN = "given";
|
||||
private static final String COMPLETED = "completed";
|
||||
private static final String REFORGED = "reforged";
|
||||
|
||||
public static void storeInBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = new Bundle();
|
||||
|
||||
node.put( SPAWNED, spawned );
|
||||
|
||||
if (spawned) {
|
||||
node.put( ALTERNATIVE, alternative );
|
||||
node.put( GIVEN, given );
|
||||
node.put( COMPLETED, completed );
|
||||
node.put( REFORGED, reforged );
|
||||
}
|
||||
|
||||
bundle.put( NODE, node );
|
||||
}
|
||||
|
||||
public static void restoreFromBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = bundle.getBundle( NODE );
|
||||
|
||||
if (!node.isNull() && (spawned = node.getBoolean( SPAWNED ))) {
|
||||
alternative = node.getBoolean( ALTERNATIVE );
|
||||
given = node.getBoolean( GIVEN );
|
||||
completed = node.getBoolean( COMPLETED );
|
||||
reforged = node.getBoolean( REFORGED );
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static void spawn( Collection<Room> rooms ) {
|
||||
if (!spawned && Dungeon.depth > 11 && Random.Int( 15 - Dungeon.depth ) == 0) {
|
||||
|
||||
Room blacksmith = null;
|
||||
for (Room r : rooms) {
|
||||
if (r.type == Type.STANDARD && r.width() > 4 && r.height() > 4) {
|
||||
blacksmith = r;
|
||||
blacksmith.type = Type.BLACKSMITH;
|
||||
|
||||
spawned = true;
|
||||
alternative = Random.Int( 2 ) == 0;
|
||||
|
||||
given = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Journal;
|
||||
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.ParalyticGas;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.armor.Armor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.quest.DriedRose;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.quest.RatSkull;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.Weapon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWeapon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.FetidRatSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.GhostSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndQuest;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndSadGhost;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Ghost extends Mob.NPC {
|
||||
|
||||
{
|
||||
name = "sad ghost";
|
||||
spriteClass = GhostSprite.class;
|
||||
|
||||
flying = true;
|
||||
|
||||
state = State.WANDERING;
|
||||
}
|
||||
|
||||
private static final String TXT_ROSE1 =
|
||||
"Hello adventurer... Once I was like you - strong and confident... " +
|
||||
"And now I'm dead... But I can't leave this place... Not until I have my _dried rose_... " +
|
||||
"It's very important to me... Some monster stole it from my body...";
|
||||
|
||||
private static final String TXT_ROSE2 =
|
||||
"Please... Help me... Find the rose...";
|
||||
|
||||
private static final String TXT_RAT1 =
|
||||
"Hello adventurer... Once I was like you - strong and confident... " +
|
||||
"And now I'm dead... But I can't leave this place... Not until I have my revenge... " +
|
||||
"Slay the _fetid rat_, that has taken my life...";
|
||||
|
||||
private static final String TXT_RAT2 =
|
||||
"Please... Help me... Slay the abomination...";
|
||||
|
||||
|
||||
public Ghost() {
|
||||
super();
|
||||
|
||||
Sample.INSTANCE.load( Assets.SND_GHOST );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseSkill( Char enemy ) {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "evaded";
|
||||
}
|
||||
|
||||
@Override
|
||||
public float speed() {
|
||||
return 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Char chooseEnemy() {
|
||||
return DUMMY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact() {
|
||||
sprite.turnTo( pos, Dungeon.hero.pos );
|
||||
|
||||
Sample.INSTANCE.play( Assets.SND_GHOST );
|
||||
|
||||
if (Quest.given) {
|
||||
|
||||
Item item = Quest.alternative ?
|
||||
Dungeon.hero.belongings.getItem( RatSkull.class ) :
|
||||
Dungeon.hero.belongings.getItem( DriedRose.class );
|
||||
if (item != null) {
|
||||
GameScene.show( new WndSadGhost( this, item ) );
|
||||
} else {
|
||||
GameScene.show( new WndQuest( this, Quest.alternative ? TXT_RAT2 : TXT_ROSE2 ) );
|
||||
|
||||
int newPos = -1;
|
||||
for (int i=0; i < 10; i++) {
|
||||
newPos = Dungeon.level.randomRespawnCell();
|
||||
if (newPos != -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (newPos != -1) {
|
||||
|
||||
Actor.freeCell( pos );
|
||||
|
||||
CellEmitter.get( pos ).start( Speck.factory( Speck.LIGHT ), 0.2f, 3 );
|
||||
pos = newPos;
|
||||
sprite.place( pos );
|
||||
sprite.visible = Dungeon.visible[pos];
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
GameScene.show( new WndQuest( this, Quest.alternative ? TXT_RAT1 : TXT_ROSE1 ) );
|
||||
Quest.given = true;
|
||||
|
||||
Journal.add( Journal.Feature.GHOST );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"The ghost is barely visible. It looks like a shapeless " +
|
||||
"spot of faint light with a sorrowful face.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Paralysis.class );
|
||||
IMMUNITIES.add( Roots.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
|
||||
public static class Quest {
|
||||
|
||||
private static boolean spawned;
|
||||
|
||||
private static boolean alternative;
|
||||
|
||||
private static boolean given;
|
||||
|
||||
private static boolean processed;
|
||||
|
||||
private static int depth;
|
||||
|
||||
private static int left2kill;
|
||||
|
||||
public static Weapon weapon;
|
||||
public static Armor armor;
|
||||
|
||||
public static void reset() {
|
||||
spawned = false;
|
||||
|
||||
weapon = null;
|
||||
armor = null;
|
||||
}
|
||||
|
||||
private static final String NODE = "sadGhost";
|
||||
|
||||
private static final String SPAWNED = "spawned";
|
||||
private static final String ALTERNATIVE = "alternative";
|
||||
private static final String LEFT2KILL = "left2kill";
|
||||
private static final String GIVEN = "given";
|
||||
private static final String PROCESSED = "processed";
|
||||
private static final String DEPTH = "depth";
|
||||
private static final String WEAPON = "weapon";
|
||||
private static final String ARMOR = "armor";
|
||||
|
||||
public static void storeInBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = new Bundle();
|
||||
|
||||
node.put( SPAWNED, spawned );
|
||||
|
||||
if (spawned) {
|
||||
|
||||
node.put( ALTERNATIVE, alternative );
|
||||
if (!alternative) {
|
||||
node.put( LEFT2KILL, left2kill );
|
||||
}
|
||||
|
||||
node.put( GIVEN, given );
|
||||
node.put( DEPTH, depth );
|
||||
node.put( PROCESSED, processed );
|
||||
|
||||
node.put( WEAPON, weapon );
|
||||
node.put( ARMOR, armor );
|
||||
}
|
||||
|
||||
bundle.put( NODE, node );
|
||||
}
|
||||
|
||||
public static void restoreFromBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = bundle.getBundle( NODE );
|
||||
|
||||
if (!node.isNull() && (spawned = node.getBoolean( SPAWNED ))) {
|
||||
|
||||
alternative = node.getBoolean( ALTERNATIVE );
|
||||
if (!alternative) {
|
||||
left2kill = node.getInt( LEFT2KILL );
|
||||
}
|
||||
|
||||
given = node.getBoolean( GIVEN );
|
||||
depth = node.getInt( DEPTH );
|
||||
processed = node.getBoolean( PROCESSED );
|
||||
|
||||
weapon = (Weapon)node.get( WEAPON );
|
||||
armor = (Armor)node.get( ARMOR );
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static void spawn( SewerLevel level ) {
|
||||
if (!spawned && Dungeon.depth > 1 && Random.Int( 5 - Dungeon.depth ) == 0) {
|
||||
|
||||
Ghost ghost = new Ghost();
|
||||
do {
|
||||
ghost.pos = level.randomRespawnCell();
|
||||
} while (ghost.pos == -1);
|
||||
level.mobs.add( ghost );
|
||||
Actor.occupyCell( ghost );
|
||||
|
||||
spawned = true;
|
||||
alternative = Random.Int( 2 ) == 0;
|
||||
if (!alternative) {
|
||||
left2kill = 8;
|
||||
}
|
||||
|
||||
given = false;
|
||||
processed = false;
|
||||
depth = Dungeon.depth;
|
||||
|
||||
do {
|
||||
weapon = (Weapon)Generator.random( Generator.Category.WEAPON );
|
||||
} while (weapon instanceof MissileWeapon);
|
||||
armor = (Armor)Generator.random( Generator.Category.ARMOR );
|
||||
|
||||
for (int i=0; i < 3; i++) {
|
||||
Item another;
|
||||
do {
|
||||
another = Generator.random( Generator.Category.WEAPON );
|
||||
} while (another instanceof MissileWeapon);
|
||||
if (another.level > weapon.level) {
|
||||
weapon = (Weapon)another;
|
||||
}
|
||||
another = Generator.random( Generator.Category.ARMOR );
|
||||
if (another.level > armor.level) {
|
||||
armor = (Armor)another;
|
||||
}
|
||||
}
|
||||
weapon.identify();
|
||||
armor.identify();
|
||||
}
|
||||
}
|
||||
|
||||
public static void process( int pos ) {
|
||||
if (spawned && given && !processed && (depth == Dungeon.depth)) {
|
||||
if (alternative) {
|
||||
|
||||
FetidRat rat = new FetidRat();
|
||||
rat.state = Mob.State.WANDERING;
|
||||
rat.pos = Dungeon.level.randomRespawnCell();
|
||||
if (rat.pos != -1) {
|
||||
GameScene.add( rat );
|
||||
processed = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (Random.Int( left2kill ) == 0) {
|
||||
Dungeon.level.drop( new DriedRose(), pos ).sprite.drop();
|
||||
processed = true;
|
||||
} else {
|
||||
left2kill--;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void complete() {
|
||||
weapon = null;
|
||||
armor = null;
|
||||
|
||||
Journal.remove( Journal.Feature.GHOST );
|
||||
}
|
||||
}
|
||||
|
||||
public static class FetidRat extends Mob {
|
||||
|
||||
{
|
||||
name = "fetid rat";
|
||||
spriteClass = FetidRatSprite.class;
|
||||
|
||||
HP = HT = 15;
|
||||
defenseSkill = 5;
|
||||
|
||||
EXP = 0;
|
||||
maxLvl = 5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return Random.NormalIntRange( 2, 6 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return 12;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int dr() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc( Char enemy, int damage ) {
|
||||
|
||||
GameScene.add( Blob.seed( pos, 20, ParalyticGas.class ) );
|
||||
|
||||
return super.defenseProc(enemy, damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
|
||||
Dungeon.level.drop( new RatSkull(), pos ).sprite.drop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"This marsupial rat is much larger, than a regular one. It is surrounded by a foul cloud.";
|
||||
}
|
||||
|
||||
private static final HashSet<Class<?>> IMMUNITIES = new HashSet<Class<?>>();
|
||||
static {
|
||||
IMMUNITIES.add( Paralysis.class );
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<Class<?>> immunities() {
|
||||
return IMMUNITIES;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Journal;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Golem;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Monk;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.quest.DwarfToken;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.rings.Ring;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.CityLevel;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ImpSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndImp;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndQuest;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Imp extends Mob.NPC {
|
||||
|
||||
{
|
||||
name = "ambitious imp";
|
||||
spriteClass = ImpSprite.class;
|
||||
}
|
||||
|
||||
private static final String TXT_GOLEMS1 =
|
||||
"Are you an adventurer? I love adventurers! You can always rely on them " +
|
||||
"if something needs to be killed. Am I right? For bounty of course ;)\n" +
|
||||
"In my case this is _golems_ who need to be killed. You see, I'm going to start a " +
|
||||
"little business here, but these stupid golems are bad for business! " +
|
||||
"It's very hard to negotiate with wandering lumps of granite, damn them! " +
|
||||
"So please, kill... let's say _6 of them_ and a reward is yours.";
|
||||
|
||||
private static final String TXT_MONKS1 =
|
||||
"Are you an adventurer? I love adventurers! You can always rely on them " +
|
||||
"if something needs to be killed. Am I right? For bounty of course ;)\n" +
|
||||
"In my case this is _monks_ who need to be killed. You see, I'm going to start a " +
|
||||
"little business here, but these lunatics don't buy anything themselves and " +
|
||||
"will scare away other customers. " +
|
||||
"So please, kill... let's say _8 of them_ and a reward is yours.";
|
||||
|
||||
private static final String TXT_GOLEMS2 =
|
||||
"How is your golem safari going?";
|
||||
|
||||
private static final String TXT_MONKS2 =
|
||||
"Oh, you are still alive! I knew that your kung-fu is stronger ;) " +
|
||||
"Just don't forget to grab these monks' tokens.";
|
||||
|
||||
private static final String TXT_CYA = "See you, %s!";
|
||||
private static final String TXT_HEY = "Psst, %s!";
|
||||
|
||||
private boolean seenBefore = false;
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
|
||||
if (!Quest.given && Dungeon.visible[pos]) {
|
||||
if (!seenBefore) {
|
||||
yell( Utils.format( TXT_HEY, Dungeon.hero.className() ) );
|
||||
}
|
||||
seenBefore = true;
|
||||
} else {
|
||||
seenBefore = false;
|
||||
}
|
||||
|
||||
throwItem();
|
||||
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseSkill( Char enemy ) {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "evaded";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact() {
|
||||
|
||||
sprite.turnTo( pos, Dungeon.hero.pos );
|
||||
if (Quest.given) {
|
||||
|
||||
DwarfToken tokens = Dungeon.hero.belongings.getItem( DwarfToken.class );
|
||||
if (tokens != null && (tokens.quantity() >= 8 || (!Quest.alternative && tokens.quantity() >= 6))) {
|
||||
GameScene.show( new WndImp( this, tokens ) );
|
||||
} else {
|
||||
tell( Quest.alternative ? TXT_MONKS2 : TXT_GOLEMS2, Dungeon.hero.className() );
|
||||
}
|
||||
|
||||
} else {
|
||||
tell( Quest.alternative ? TXT_MONKS1 : TXT_GOLEMS1 );
|
||||
Quest.given = true;
|
||||
Quest.completed = false;
|
||||
|
||||
Journal.add( Journal.Feature.IMP );
|
||||
}
|
||||
}
|
||||
|
||||
private void tell( String format, Object...args ) {
|
||||
GameScene.show(
|
||||
new WndQuest( this, Utils.format( format, args ) ) );
|
||||
}
|
||||
|
||||
public void flee() {
|
||||
|
||||
yell( Utils.format( TXT_CYA, Dungeon.hero.className() ) );
|
||||
|
||||
destroy();
|
||||
sprite.die();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Imps are lesser demons. They are notable for neither their strength nor their magic talent, " +
|
||||
"but they are quite smart and sociable. Many imps prefer to live among non-demons.";
|
||||
}
|
||||
|
||||
public static class Quest {
|
||||
|
||||
private static boolean alternative;
|
||||
|
||||
private static boolean spawned;
|
||||
private static boolean given;
|
||||
private static boolean completed;
|
||||
|
||||
public static Ring reward;
|
||||
|
||||
public static void reset() {
|
||||
spawned = false;
|
||||
|
||||
reward = null;
|
||||
}
|
||||
|
||||
private static final String NODE = "demon";
|
||||
|
||||
private static final String ALTERNATIVE = "alternative";
|
||||
private static final String SPAWNED = "spawned";
|
||||
private static final String GIVEN = "given";
|
||||
private static final String COMPLETED = "completed";
|
||||
private static final String REWARD = "reward";
|
||||
|
||||
public static void storeInBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = new Bundle();
|
||||
|
||||
node.put( SPAWNED, spawned );
|
||||
|
||||
if (spawned) {
|
||||
node.put( ALTERNATIVE, alternative );
|
||||
|
||||
node.put( GIVEN, given );
|
||||
node.put( COMPLETED, completed );
|
||||
node.put( REWARD, reward );
|
||||
}
|
||||
|
||||
bundle.put( NODE, node );
|
||||
}
|
||||
|
||||
public static void restoreFromBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = bundle.getBundle( NODE );
|
||||
|
||||
if (!node.isNull() && (spawned = node.getBoolean( SPAWNED ))) {
|
||||
alternative = node.getBoolean( ALTERNATIVE );
|
||||
|
||||
given = node.getBoolean( GIVEN );
|
||||
completed = node.getBoolean( COMPLETED );
|
||||
reward = (Ring)node.get( REWARD );
|
||||
}
|
||||
}
|
||||
|
||||
public static void spawn( CityLevel level, Room room ) {
|
||||
if (!spawned && Dungeon.depth > 16 && Random.Int( 20 - Dungeon.depth ) == 0) {
|
||||
|
||||
Imp npc = new Imp();
|
||||
do {
|
||||
npc.pos = level.randomRespawnCell();
|
||||
} while (npc.pos == -1 || level.heaps.get( npc.pos ) != null);
|
||||
level.mobs.add( npc );
|
||||
Actor.occupyCell( npc );
|
||||
|
||||
spawned = true;
|
||||
alternative = Random.Int( 2 ) == 0;
|
||||
|
||||
given = false;
|
||||
|
||||
do {
|
||||
reward = (Ring)Generator.random( Generator.Category.RING );
|
||||
} while (reward.cursed);
|
||||
reward.upgrade( 2 );
|
||||
reward.cursed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void process( Mob mob ) {
|
||||
if (spawned && given && !completed) {
|
||||
if ((alternative && mob instanceof Monk) ||
|
||||
(!alternative && mob instanceof Golem)) {
|
||||
|
||||
Dungeon.level.drop( new DwarfToken(), mob.pos ).sprite.drop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void complete() {
|
||||
reward = null;
|
||||
completed = true;
|
||||
|
||||
Journal.remove( Journal.Feature.IMP );
|
||||
}
|
||||
|
||||
public static boolean isCompleted() {
|
||||
return completed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ImpSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
|
||||
public class ImpShopkeeper extends Shopkeeper {
|
||||
|
||||
private static final String TXT_GREETINGS = "Hello, friend!";
|
||||
|
||||
{
|
||||
name = "ambitious imp";
|
||||
spriteClass = ImpSprite.class;
|
||||
}
|
||||
|
||||
private boolean seenBefore = false;
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
|
||||
if (!seenBefore && Dungeon.visible[pos]) {
|
||||
yell( Utils.format( TXT_GREETINGS ) );
|
||||
seenBefore = true;
|
||||
}
|
||||
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void flee() {
|
||||
for (Heap heap: Dungeon.level.heaps.values()) {
|
||||
if (heap.type == Heap.Type.FOR_SALE) {
|
||||
CellEmitter.get( heap.pos ).burst( ElmoParticle.FACTORY, 4 );
|
||||
heap.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
destroy();
|
||||
|
||||
sprite.emitter().burst( Speck.factory( Speck.WOOL ), 15 );
|
||||
sprite.killAndErase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"Imps are lesser demons. They are notable for neither their strength nor their magic talent. " +
|
||||
"But they are quite smart and sociable, and many of imps prefer to live and do business among non-demons.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.CharSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.MirrorSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class MirrorImage extends Mob.NPC {
|
||||
|
||||
{
|
||||
name = "mirror image";
|
||||
spriteClass = MirrorSprite.class;
|
||||
|
||||
state = State.HUNTING;
|
||||
|
||||
enemy = DUMMY;
|
||||
}
|
||||
|
||||
public int tier;
|
||||
|
||||
private int attack;
|
||||
private int damage;
|
||||
|
||||
private static final String TIER = "tier";
|
||||
private static final String ATTACK = "attack";
|
||||
private static final String DAMAGE = "damage";
|
||||
|
||||
@Override
|
||||
public void storeInBundle( Bundle bundle ) {
|
||||
super.storeInBundle( bundle );
|
||||
bundle.put( TIER, tier );
|
||||
bundle.put( ATTACK, attack );
|
||||
bundle.put( DAMAGE, damage );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle( Bundle bundle ) {
|
||||
super.restoreFromBundle( bundle );
|
||||
tier = bundle.getInt( TIER );
|
||||
attack = bundle.getInt( ATTACK );
|
||||
damage = bundle.getInt( DAMAGE );
|
||||
}
|
||||
|
||||
public void duplicate( Hero hero ) {
|
||||
tier = hero.tier();
|
||||
attack = hero.attackSkill( hero );
|
||||
damage = hero.damageRoll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackSkill( Char target ) {
|
||||
return attack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageRoll() {
|
||||
return damage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int attackProc( Char enemy, int damage ) {
|
||||
int dmg = super.attackProc( enemy, damage );
|
||||
|
||||
destroy();
|
||||
sprite.die();
|
||||
|
||||
return dmg;
|
||||
}
|
||||
|
||||
protected Char chooseEnemy() {
|
||||
|
||||
if (enemy == DUMMY || !enemy.isAlive()) {
|
||||
HashSet<Mob> enemies = new HashSet<Mob>();
|
||||
for (Mob mob:Dungeon.level.mobs) {
|
||||
if (mob.hostile && Level.fieldOfView[mob.pos]) {
|
||||
enemies.add( mob );
|
||||
}
|
||||
}
|
||||
|
||||
enemy = enemies.size() > 0 ? Random.element( enemies ) : DUMMY;
|
||||
}
|
||||
|
||||
return enemy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"This illusion bears a close resemblance to you, " +
|
||||
"but it's paler and twitches a little.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSprite sprite() {
|
||||
CharSprite s = super.sprite();
|
||||
((MirrorSprite)s).updateArmor( tier );
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact() {
|
||||
|
||||
int curPos = pos;
|
||||
|
||||
moveSprite( pos, Dungeon.hero.pos );
|
||||
move( Dungeon.hero.pos );
|
||||
|
||||
Dungeon.hero.sprite.move( Dungeon.hero.pos, curPos );
|
||||
Dungeon.hero.move( curPos );
|
||||
|
||||
Dungeon.hero.spend( 1 / Dungeon.hero.speed() );
|
||||
Dungeon.hero.busy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.RatKingSprite;
|
||||
|
||||
public class RatKing extends Mob.NPC {
|
||||
|
||||
{
|
||||
name = "rat king";
|
||||
spriteClass = RatKingSprite.class;
|
||||
|
||||
state = State.SLEEPING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseSkill( Char enemy ) {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float speed() {
|
||||
return 2f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Char chooseEnemy() {
|
||||
return DUMMY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact() {
|
||||
sprite.turnTo( pos, Dungeon.hero.pos );
|
||||
if (state == State.SLEEPING) {
|
||||
notice();
|
||||
yell( "I'm not sleeping!" );
|
||||
state = State.WANDERING;
|
||||
} else {
|
||||
yell( "What is it? I have no time for this nonsense. My kingdom won't rule itself!" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"This rat is a little bigger than a regular marsupial rat " +
|
||||
"and it's wearing a tiny crown on its head.";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ShopkeeperSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndBag;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndTradeItem;
|
||||
|
||||
public class Shopkeeper extends Mob.NPC {
|
||||
|
||||
{
|
||||
name = "shopkeeper";
|
||||
spriteClass = ShopkeeperSprite.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
|
||||
throwItem();
|
||||
|
||||
sprite.turnTo( pos, Dungeon.hero.pos );
|
||||
spend( TICK );
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
flee();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
flee();
|
||||
}
|
||||
|
||||
protected void flee() {
|
||||
for (Heap heap: Dungeon.level.heaps.values()) {
|
||||
if (heap.type == Heap.Type.FOR_SALE) {
|
||||
CellEmitter.get( heap.pos ).burst( ElmoParticle.FACTORY, 4 );
|
||||
heap.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
destroy();
|
||||
|
||||
sprite.killAndErase();
|
||||
CellEmitter.get( pos ).burst( ElmoParticle.FACTORY, 6 );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"This stout guy looks more appropriate for a trade district in some large city " +
|
||||
"than for a dungeon. His prices explain why he prefers to do business here.";
|
||||
}
|
||||
|
||||
public static WndBag sell() {
|
||||
return GameScene.selectItem( itemSelector, WndBag.Mode.FOR_SALE, "Select an item to sell" );
|
||||
}
|
||||
|
||||
private static WndBag.Listener itemSelector = new WndBag.Listener() {
|
||||
@Override
|
||||
public void onSelect( Item item ) {
|
||||
if (item != null) {
|
||||
WndBag parentWnd = sell();
|
||||
GameScene.show( new WndTradeItem( item, parentWnd ) );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void interact() {
|
||||
sell();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2014 Oleg Dolya
|
||||
*
|
||||
* 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.npcs;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.watabou.noosa.audio.Sample;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Journal;
|
||||
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.ToxicGas;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Roots;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.bags.Bag;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfStrength;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.quest.CorpseDust;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfAmok;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfAvalanche;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlink;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfDisintegration;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfFirebolt;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfLightning;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfPoison;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfRegrowth;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfSlowness;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfTelekinesis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Room;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.WandmakerSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.Utils;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndQuest;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.windows.WndWandmaker;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class Wandmaker extends Mob.NPC {
|
||||
|
||||
{
|
||||
name = "old wandmaker";
|
||||
spriteClass = WandmakerSprite.class;
|
||||
}
|
||||
|
||||
private static final String TXT_BERRY1 =
|
||||
"Oh, what a pleasant surprise to meet a decent person in such place! I came here for a rare ingredient - " +
|
||||
"a _Rotberry seed_. Being a magic user, I'm quite able to defend myself against local monsters, " +
|
||||
"but I'm getting lost in no time, it's very embarrassing. Probably you could help me? I would be " +
|
||||
"happy to pay for your service with one of my best wands.";
|
||||
|
||||
private static final String TXT_DUST1 =
|
||||
"Oh, what a pleasant surprise to meet a decent person in such place! I came here for a rare ingredient - " +
|
||||
"_corpse dust_. It can be gathered from skeletal remains and there is an ample number of them in the dungeon. " +
|
||||
"Being a magic user, I'm quite able to defend myself against local monsters, but I'm getting lost in no time, " +
|
||||
"it's very embarrassing. Probably you could help me? I would be happy to pay for your service with one of my best wands.";
|
||||
|
||||
private static final String TXT_BERRY2 =
|
||||
"Any luck with a Rotberry seed, %s? No? Don't worry, I'm not in a hurry.";
|
||||
|
||||
private static final String TXT_DUST2 =
|
||||
"Any luck with corpse dust, %s? Bone piles are the most obvious places to look.";
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
throwItem();
|
||||
return super.act();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseSkill( Char enemy ) {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defenseVerb() {
|
||||
return "absorbed";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage( int dmg, Object src ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add( Buff buff ) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean reset() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interact() {
|
||||
|
||||
sprite.turnTo( pos, Dungeon.hero.pos );
|
||||
if (Quest.given) {
|
||||
|
||||
Item item = Quest.alternative ?
|
||||
Dungeon.hero.belongings.getItem( CorpseDust.class ) :
|
||||
Dungeon.hero.belongings.getItem( Rotberry.Seed.class );
|
||||
if (item != null) {
|
||||
GameScene.show( new WndWandmaker( this, item ) );
|
||||
} else {
|
||||
tell( Quest.alternative ? TXT_DUST2 : TXT_BERRY2, Dungeon.hero.className() );
|
||||
}
|
||||
|
||||
} else {
|
||||
tell( Quest.alternative ? TXT_DUST1 : TXT_BERRY1 );
|
||||
Quest.given = true;
|
||||
|
||||
Quest.placeItem();
|
||||
|
||||
Journal.add( Journal.Feature.WANDMAKER );
|
||||
}
|
||||
}
|
||||
|
||||
private void tell( String format, Object...args ) {
|
||||
GameScene.show( new WndQuest( this, Utils.format( format, args ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
return
|
||||
"This old but hale gentleman wears a slightly confused " +
|
||||
"expression. He is protected by a magic shield.";
|
||||
}
|
||||
|
||||
public static class Quest {
|
||||
|
||||
private static boolean spawned;
|
||||
|
||||
private static boolean alternative;
|
||||
|
||||
private static boolean given;
|
||||
|
||||
public static Wand wand1;
|
||||
public static Wand wand2;
|
||||
|
||||
public static void reset() {
|
||||
spawned = false;
|
||||
|
||||
wand1 = null;
|
||||
wand2 = null;
|
||||
}
|
||||
|
||||
private static final String NODE = "wandmaker";
|
||||
|
||||
private static final String SPAWNED = "spawned";
|
||||
private static final String ALTERNATIVE = "alternative";
|
||||
private static final String GIVEN = "given";
|
||||
private static final String WAND1 = "wand1";
|
||||
private static final String WAND2 = "wand2";
|
||||
|
||||
public static void storeInBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = new Bundle();
|
||||
|
||||
node.put( SPAWNED, spawned );
|
||||
|
||||
if (spawned) {
|
||||
|
||||
node.put( ALTERNATIVE, alternative );
|
||||
|
||||
node.put(GIVEN, given );
|
||||
|
||||
node.put( WAND1, wand1 );
|
||||
node.put( WAND2, wand2 );
|
||||
}
|
||||
|
||||
bundle.put( NODE, node );
|
||||
}
|
||||
|
||||
public static void restoreFromBundle( Bundle bundle ) {
|
||||
|
||||
Bundle node = bundle.getBundle( NODE );
|
||||
|
||||
if (!node.isNull() && (spawned = node.getBoolean( SPAWNED ))) {
|
||||
|
||||
alternative = node.getBoolean( ALTERNATIVE );
|
||||
|
||||
given = node.getBoolean( GIVEN );
|
||||
|
||||
wand1 = (Wand)node.get( WAND1 );
|
||||
wand2 = (Wand)node.get( WAND2 );
|
||||
} else {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
public static void spawn( PrisonLevel level, Room room ) {
|
||||
if (!spawned && Dungeon.depth > 6 && Random.Int( 10 - Dungeon.depth ) == 0) {
|
||||
|
||||
Wandmaker npc = new Wandmaker();
|
||||
do {
|
||||
npc.pos = room.random();
|
||||
} while (level.map[npc.pos] == Terrain.ENTRANCE || level.map[npc.pos] == Terrain.SIGN);
|
||||
level.mobs.add( npc );
|
||||
Actor.occupyCell( npc );
|
||||
|
||||
spawned = true;
|
||||
alternative = Random.Int( 2 ) == 0;
|
||||
|
||||
given = false;
|
||||
|
||||
switch (Random.Int( 5 )) {
|
||||
case 0:
|
||||
wand1 = new WandOfAvalanche();
|
||||
break;
|
||||
case 1:
|
||||
wand1 = new WandOfDisintegration();
|
||||
break;
|
||||
case 2:
|
||||
wand1 = new WandOfFirebolt();
|
||||
break;
|
||||
case 3:
|
||||
wand1 = new WandOfLightning();
|
||||
break;
|
||||
case 4:
|
||||
wand1 = new WandOfPoison();
|
||||
break;
|
||||
}
|
||||
wand1.random().upgrade();
|
||||
|
||||
switch (Random.Int( 5 )) {
|
||||
case 0:
|
||||
wand2 = new WandOfAmok();
|
||||
break;
|
||||
case 1:
|
||||
wand2 = new WandOfBlink();
|
||||
break;
|
||||
case 2:
|
||||
wand2 = new WandOfRegrowth();
|
||||
break;
|
||||
case 3:
|
||||
wand2 = new WandOfSlowness();
|
||||
break;
|
||||
case 4:
|
||||
wand2 = new WandOfTelekinesis();
|
||||
break;
|
||||
}
|
||||
wand2.random().upgrade();
|
||||
}
|
||||
}
|
||||
|
||||
public static void placeItem() {
|
||||
if (alternative) {
|
||||
|
||||
ArrayList<Heap> candidates = new ArrayList<Heap>();
|
||||
for (Heap heap : Dungeon.level.heaps.values()) {
|
||||
if (heap.type == Heap.Type.SKELETON && !Dungeon.visible[heap.pos]) {
|
||||
candidates.add( heap );
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.size() > 0) {
|
||||
Random.element( candidates ).drop( new CorpseDust() );
|
||||
} else {
|
||||
int pos = Dungeon.level.randomRespawnCell();
|
||||
while (Dungeon.level.heaps.get( pos ) != null) {
|
||||
pos = Dungeon.level.randomRespawnCell();
|
||||
}
|
||||
|
||||
Heap heap = Dungeon.level.drop( new CorpseDust(), pos );
|
||||
heap.type = Heap.Type.SKELETON;
|
||||
heap.sprite.link();
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
int shrubPos = Dungeon.level.randomRespawnCell();
|
||||
while (Dungeon.level.heaps.get( shrubPos ) != null) {
|
||||
shrubPos = Dungeon.level.randomRespawnCell();
|
||||
}
|
||||
Dungeon.level.plant( new Rotberry.Seed(), shrubPos );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static void complete() {
|
||||
wand1 = null;
|
||||
wand2 = null;
|
||||
|
||||
Journal.remove( Journal.Feature.WANDMAKER );
|
||||
}
|
||||
}
|
||||
|
||||
public static class Rotberry extends Plant {
|
||||
|
||||
private static final String TXT_DESC =
|
||||
"Berries of this shrub taste like sweet, sweet death.";
|
||||
|
||||
{
|
||||
image = 7;
|
||||
plantName = "Rotberry";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void activate( Char ch ) {
|
||||
super.activate( ch );
|
||||
|
||||
GameScene.add( Blob.seed( pos, 100, ToxicGas.class ) );
|
||||
|
||||
Dungeon.level.drop( new Seed(), pos ).sprite.drop();
|
||||
|
||||
if (ch != null) {
|
||||
Buff.prolong( ch, Roots.class, TICK * 3 );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String desc() {
|
||||
return TXT_DESC;
|
||||
}
|
||||
|
||||
public static class Seed extends Plant.Seed {
|
||||
{
|
||||
plantName = "Rotberry";
|
||||
|
||||
name = "seed of " + plantName;
|
||||
image = ItemSpriteSheet.SEED_ROTBERRY;
|
||||
|
||||
plantClass = Rotberry.class;
|
||||
alchemyClass = PotionOfStrength.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collect( Bag container ) {
|
||||
if (super.collect( container )) {
|
||||
|
||||
if (Dungeon.level != null) {
|
||||
for (Mob mob : Dungeon.level.mobs) {
|
||||
mob.beckon( Dungeon.hero.pos );
|
||||
}
|
||||
|
||||
GLog.w( "The seed emits a roar that echoes throughout the dungeon!" );
|
||||
CellEmitter.center( Dungeon.hero.pos ).start( Speck.factory( Speck.SCREAM ), 0.3f, 3 );
|
||||
Sample.INSTANCE.play( Assets.SND_CHALLENGE );
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String desc() {
|
||||
return TXT_DESC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user