v2.1.0: added a new exotic enemy: phantom piranhas (some text missing)
This commit is contained in:
@@ -1197,6 +1197,10 @@ actors.mobs.monk.desc=These monks are fanatics, who have devoted themselves to p
|
||||
actors.mobs.monk$focus.name=focused
|
||||
actors.mobs.monk$focus.desc=This monk is perfectly honed in on their target, and seem to be anticipating their moves before they make them.\n\nWhile focused, the next physical attack made against this character is guaranteed to miss, no matter what circumstances there are. Parrying this attack will spend the monk's focus, and they will need to build it up again to parry another attack. Monks build focus more quickly while they are moving.
|
||||
|
||||
actors.mobs.phantompiranha.name=phantom piranha
|
||||
actors.mobs.phantompiranha.teleport_away=The phantom piranha teleports away...
|
||||
actors.mobs.phantompiranha.desc=TODO
|
||||
|
||||
actors.mobs.piranha.name=giant piranha
|
||||
actors.mobs.piranha.desc=These carnivorous fish are not natural inhabitants of underground pools. They were bred specifically to protect flooded treasure vaults.
|
||||
|
||||
|
||||
@@ -568,6 +568,9 @@ items.food.mysterymeat.stuffed=You are stuffed.
|
||||
items.food.mysterymeat.desc=Eat at your own risk!
|
||||
items.food.mysterymeat$placeholder.name=meat
|
||||
|
||||
items.food.phantommeat.name=phantom meat
|
||||
items.food.phantommeat.desc=TODO
|
||||
|
||||
items.food.pasty.pasty=pasty
|
||||
items.food.pasty.pie=pumpkin pie
|
||||
items.food.pasty.cane=candy cane
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 543 B After Width: | Height: | Size: 9.4 KiB |
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2023 Evan Debenham
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.PhantomMeat;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportation;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.Wand;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.PhantomPiranhaSprite;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||
import com.watabou.utils.PathFinder;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PhantomPiranha extends Piranha {
|
||||
|
||||
{
|
||||
spriteClass = PhantomPiranhaSprite.class;
|
||||
|
||||
loot = PhantomMeat.class;
|
||||
lootChance = 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
Char dmgSource = null;
|
||||
if (src instanceof Char) dmgSource = (Char)src;
|
||||
if (src instanceof Wand) dmgSource = Dungeon.hero;
|
||||
|
||||
if (dmgSource == null || !Dungeon.level.adjacent(pos, dmgSource.pos)){
|
||||
dmg = Math.round(dmg/2f); //halve damage taken if we are going to teleport
|
||||
}
|
||||
super.damage(dmg, src);
|
||||
|
||||
if (isAlive()) {
|
||||
if (dmgSource != null) {
|
||||
if (!Dungeon.level.adjacent(pos, dmgSource.pos)) {
|
||||
ArrayList<Integer> candidates = new ArrayList<>();
|
||||
for (int i : PathFinder.NEIGHBOURS8) {
|
||||
if (Dungeon.level.water[dmgSource.pos + i] && Actor.findChar(dmgSource.pos + i) == null) {
|
||||
candidates.add(dmgSource.pos + i);
|
||||
}
|
||||
}
|
||||
if (!candidates.isEmpty()) {
|
||||
ScrollOfTeleportation.appear(this, Random.element(candidates));
|
||||
aggro(dmgSource);
|
||||
} else {
|
||||
teleportAway();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
teleportAway();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int defenseProc(Char enemy, int damage) {
|
||||
return super.defenseProc(enemy, damage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dieOnLand() {
|
||||
teleportAway();
|
||||
}
|
||||
|
||||
private void teleportAway(){
|
||||
|
||||
ArrayList<Integer> inFOVCandidates = new ArrayList<>();
|
||||
ArrayList<Integer> outFOVCandidates = new ArrayList<>();
|
||||
for (int i = 0; i < Dungeon.level.length(); i++){
|
||||
if (Dungeon.level.water[i] && Actor.findChar(i) == null){
|
||||
if (Dungeon.level.heroFOV[i]){
|
||||
inFOVCandidates.add(i);
|
||||
} else {
|
||||
outFOVCandidates.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!outFOVCandidates.isEmpty()){
|
||||
ScrollOfTeleportation.appear(this, Random.element(outFOVCandidates));
|
||||
GLog.i(Messages.get(this, "teleport_away"));
|
||||
} else if (!inFOVCandidates.isEmpty()){
|
||||
ScrollOfTeleportation.appear(this, Random.element(inFOVCandidates));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ public class Piranha extends Mob {
|
||||
protected boolean act() {
|
||||
|
||||
if (!Dungeon.level.water[pos]) {
|
||||
die( null );
|
||||
dieOnLand();
|
||||
return true;
|
||||
} else {
|
||||
return super.act();
|
||||
@@ -99,7 +99,11 @@ public class Piranha extends Mob {
|
||||
}
|
||||
return super.surprisedBy(enemy, attacking);
|
||||
}
|
||||
|
||||
|
||||
public void dieOnLand(){
|
||||
die( null );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die( Object cause ) {
|
||||
super.die( cause );
|
||||
@@ -191,4 +195,12 @@ public class Piranha extends Mob {
|
||||
return super.act(enemyInFOV, justAlerted);
|
||||
}
|
||||
}
|
||||
|
||||
public static Piranha random(){
|
||||
if (Random.Int(50) == 0){
|
||||
return new PhantomPiranha();
|
||||
} else {
|
||||
return new Piranha();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.food.Blandfruit;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.Food;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.MeatPie;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.Pasty;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.food.PhantomMeat;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEnergy;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
@@ -217,8 +218,8 @@ public class HornOfPlenty extends Artifact {
|
||||
if (level() >= 10) return;
|
||||
|
||||
storedFoodEnergy += food.energy;
|
||||
//Pasties are worth two upgrades instead of 1.5, meat pies are worth 4 instead of 3!
|
||||
if (food instanceof Pasty){
|
||||
//Pasties and phantom meat are worth two upgrades instead of 1.5, meat pies are worth 4 instead of 3!
|
||||
if (food instanceof Pasty || food instanceof PhantomMeat){
|
||||
storedFoodEnergy += Hunger.HUNGRY/2;
|
||||
} else if (food instanceof MeatPie){
|
||||
storedFoodEnergy += Hunger.HUNGRY;
|
||||
|
||||
@@ -58,7 +58,7 @@ public class MeatPie extends Food {
|
||||
|
||||
for (Item ingredient : ingredients){
|
||||
if (ingredient.quantity() > 0) {
|
||||
if (ingredient instanceof Pasty) {
|
||||
if (ingredient instanceof Pasty || ingredient instanceof PhantomMeat) {
|
||||
pasty = true;
|
||||
} else if (ingredient.getClass() == Food.class) {
|
||||
ration = true;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2023 Evan Debenham
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.items.food;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Barkskin;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Hunger;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Invisibility;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.Hero;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
|
||||
|
||||
public class PhantomMeat extends Food {
|
||||
|
||||
{
|
||||
image = ItemSpriteSheet.PHANTOM_MEAT;
|
||||
energy = Hunger.STARVING;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void satisfy(Hero hero) {
|
||||
super.satisfy(hero);
|
||||
effect(hero);
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return 30 * quantity;
|
||||
}
|
||||
|
||||
public static void effect(Hero hero){
|
||||
|
||||
Buff.affect( hero, Barkskin.class ).set( hero.HT / 4, 1 );
|
||||
Buff.affect( hero, Invisibility.class, Invisibility.DURATION );
|
||||
if (hero.HP < hero.HT) {
|
||||
hero.HP = Math.min( hero.HP + hero.HT / 4, hero.HT );
|
||||
}
|
||||
hero.sprite.emitter().burst( Speck.factory( Speck.HEALING ), 1 );
|
||||
PotionOfHealing.cure(hero);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1081,7 +1081,7 @@ public abstract class Level implements Bundlable {
|
||||
}
|
||||
|
||||
if (ch.isAlive() && ch instanceof Piranha && !water[ch.pos]){
|
||||
ch.die(null);
|
||||
((Piranha) ch).dieOnLand();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ public class PoolRoom extends SpecialRoom {
|
||||
level.addItemToSpawn( new PotionOfInvisibility() );
|
||||
|
||||
for (int i=0; i < NPIRANHAS; i++) {
|
||||
Piranha piranha = new Piranha();
|
||||
Piranha piranha = Piranha.random();
|
||||
do {
|
||||
piranha.pos = level.pointToCell(random());
|
||||
} while (level.map[piranha.pos] != Terrain.WATER|| level.findMob( piranha.pos ) != null);
|
||||
|
||||
@@ -65,7 +65,7 @@ public class AquariumRoom extends StandardRoom {
|
||||
int numFish = (minDim - 4)/3; //1-3 fish, depending on room size
|
||||
|
||||
for (int i=0; i < numFish; i++) {
|
||||
Piranha piranha = new Piranha();
|
||||
Piranha piranha = Piranha.random();
|
||||
do {
|
||||
piranha.pos = level.pointToCell(random(3));
|
||||
} while (level.map[piranha.pos] != Terrain.WATER|| level.findMob( piranha.pos ) != null);
|
||||
|
||||
@@ -120,7 +120,7 @@ public class DistortionTrap extends Trap{
|
||||
continue; //wraiths spawn themselves, no need to do more
|
||||
case 1:
|
||||
//yes it's intended that these are likely to die right away
|
||||
mob = new Piranha();
|
||||
mob = Piranha.random();
|
||||
break;
|
||||
case 2:
|
||||
mob = Mimic.spawnAt(point, new ArrayList<>());
|
||||
|
||||
@@ -645,6 +645,7 @@ public class ItemSpriteSheet {
|
||||
public static final int BLANDFRUIT = FOOD+10;
|
||||
public static final int BLAND_CHUNKS= FOOD+11;
|
||||
public static final int BERRY = FOOD+12;
|
||||
public static final int PHANTOM_MEAT= FOOD+13;
|
||||
static{
|
||||
assignItemRect(MEAT, 15, 11);
|
||||
assignItemRect(STEAK, 15, 11);
|
||||
@@ -659,6 +660,7 @@ public class ItemSpriteSheet {
|
||||
assignItemRect(BLANDFRUIT, 9, 12);
|
||||
assignItemRect(BLAND_CHUNKS,14, 6);
|
||||
assignItemRect(BERRY, 9, 11);
|
||||
assignItemRect(PHANTOM_MEAT,15, 11);
|
||||
}
|
||||
|
||||
private static final int QUEST = xy(1, 29); //32 slots
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2023 Evan Debenham
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||
import com.watabou.noosa.MovieClip;
|
||||
import com.watabou.noosa.TextureFilm;
|
||||
import com.watabou.noosa.particles.Emitter;
|
||||
|
||||
public class PhantomPiranhaSprite extends MobSprite {
|
||||
|
||||
private Emitter sparkles;
|
||||
|
||||
public PhantomPiranhaSprite() {
|
||||
super();
|
||||
|
||||
renderShadow = false;
|
||||
perspectiveRaise = 0.2f;
|
||||
|
||||
texture( Assets.Sprites.PIRANHA );
|
||||
|
||||
TextureFilm frames = new TextureFilm( texture, 12, 16 );
|
||||
|
||||
int c = 21;
|
||||
|
||||
idle = new MovieClip.Animation( 8, true );
|
||||
idle.frames( frames, c+0, c+1, c+2, c+1 );
|
||||
|
||||
run = new MovieClip.Animation( 20, true );
|
||||
run.frames( frames, c+0, c+1, c+2, c+1 );
|
||||
|
||||
attack = new MovieClip.Animation( 20, false );
|
||||
attack.frames( frames, c+3, c+4, c+5, c+6, c+7, c+8, c+9, c+10, c+11 );
|
||||
|
||||
die = new MovieClip.Animation( 4, false );
|
||||
die.frames( frames, c+12, c+13, c+14 );
|
||||
|
||||
play( idle );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link(Char ch) {
|
||||
super.link(ch);
|
||||
renderShadow = false;
|
||||
|
||||
if (sparkles == null) {
|
||||
sparkles = emitter();
|
||||
sparkles.pour( Speck.factory( Speck.LIGHT ), 0.5f );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
|
||||
if (sparkles != null) {
|
||||
sparkles.visible = visible;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
|
||||
if (sparkles != null) {
|
||||
sparkles.on = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kill() {
|
||||
super.kill();
|
||||
|
||||
if (sparkles != null) {
|
||||
sparkles.on = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete( MovieClip.Animation anim ) {
|
||||
super.onComplete( anim );
|
||||
|
||||
if (anim == attack) {
|
||||
GameScene.ripple( ch.pos );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user