v0.7.5: initial tengu rework implementation. Needs balance and phase 3
This commit is contained in:
parent
96dd6eff82
commit
309b7357b2
BIN
android/src/main/assets/custom_tiles/prison_exit_new.png
Normal file
BIN
android/src/main/assets/custom_tiles/prison_exit_new.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
@ -124,10 +124,11 @@ public class Assets {
|
||||||
public static final String LOADING_CITY = "loading_city.png";
|
public static final String LOADING_CITY = "loading_city.png";
|
||||||
public static final String LOADING_HALLS = "loading_halls.png";
|
public static final String LOADING_HALLS = "loading_halls.png";
|
||||||
|
|
||||||
public static final String WEAK_FLOOR = "custom_tiles/weak_floor.png";
|
public static final String WEAK_FLOOR = "custom_tiles/weak_floor.png";
|
||||||
public static final String SEWER_BOSS = "custom_tiles/sewer_boss.png";
|
public static final String SEWER_BOSS = "custom_tiles/sewer_boss.png";
|
||||||
public static final String PRISON_QUEST = "custom_tiles/prison_quests.png";
|
public static final String PRISON_QUEST = "custom_tiles/prison_quests.png";
|
||||||
public static final String PRISON_EXIT = "custom_tiles/prison_exit.png";
|
public static final String PRISON_EXIT_OLD = "custom_tiles/prison_exit_old.png";
|
||||||
|
public static final String PRISON_EXIT_NEW = "custom_tiles/prison_exit_new.png";
|
||||||
|
|
||||||
public static final String BUFFS_SMALL = "buffs.png";
|
public static final String BUFFS_SMALL = "buffs.png";
|
||||||
public static final String BUFFS_LARGE = "large_buffs.png";
|
public static final String BUFFS_LARGE = "large_buffs.png";
|
||||||
|
|
|
@ -53,7 +53,7 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.HallsLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.LastLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.LastLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.LastShopLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.LastShopLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonBossLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.NewPrisonBossLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerBossLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.SewerLevel;
|
||||||
|
@ -253,7 +253,7 @@ public class Dungeon {
|
||||||
level = new PrisonLevel();
|
level = new PrisonLevel();
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
level = new PrisonBossLevel();
|
level = new NewPrisonBossLevel();
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
case 12:
|
case 12:
|
||||||
|
|
|
@ -102,6 +102,12 @@ public class ShatteredPixelDungeon extends Game {
|
||||||
com.watabou.utils.Bundle.addAlias(
|
com.watabou.utils.Bundle.addAlias(
|
||||||
com.shatteredpixel.shatteredpixeldungeon.levels.rooms.sewerboss.SewerBossEntranceRoom.class,
|
com.shatteredpixel.shatteredpixeldungeon.levels.rooms.sewerboss.SewerBossEntranceRoom.class,
|
||||||
"com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.SewerBossEntranceRoom" );
|
"com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.SewerBossEntranceRoom" );
|
||||||
|
com.watabou.utils.Bundle.addAlias(
|
||||||
|
com.shatteredpixel.shatteredpixeldungeon.levels.OldPrisonBossLevel.class,
|
||||||
|
"com.shatteredpixel.shatteredpixeldungeon.levels.OldPrisonBossLevel" );
|
||||||
|
com.watabou.utils.Bundle.addAlias(
|
||||||
|
com.shatteredpixel.shatteredpixeldungeon.actors.mobs.OldTengu.class,
|
||||||
|
"com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Tengu" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,315 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 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.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.buffs.LockedFloor;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.hero.HeroSubClass;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.items.TomeOfMastery;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.LloydsBeacon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.NewPrisonBossLevel;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.sprites.TenguSprite;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
|
||||||
|
import com.watabou.noosa.audio.Sample;
|
||||||
|
import com.watabou.utils.Bundle;
|
||||||
|
import com.watabou.utils.Random;
|
||||||
|
|
||||||
|
//TODO currently has attack/defence stats for testing, need to add those
|
||||||
|
public class NewTengu extends Mob {
|
||||||
|
|
||||||
|
{
|
||||||
|
spriteClass = TenguSprite.class;
|
||||||
|
|
||||||
|
HP = HT = 160;
|
||||||
|
EXP = 20;
|
||||||
|
defenseSkill = 0;
|
||||||
|
|
||||||
|
HUNTING = new Hunting();
|
||||||
|
|
||||||
|
flying = true; //doesn't literally fly, but he is fleet-of-foot enough to avoid hazards
|
||||||
|
|
||||||
|
properties.add(Property.BOSS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onAdd() {
|
||||||
|
//when he's removed and re-added to the fight, his time is always set to now.
|
||||||
|
spend(-cooldown());
|
||||||
|
super.onAdd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int damageRoll() {
|
||||||
|
return Random.NormalIntRange( 0, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int attackSkill( Char target ) {
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int drRoll() {
|
||||||
|
return Random.NormalIntRange(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void damage(int dmg, Object src) {
|
||||||
|
NewPrisonBossLevel.State state = ((NewPrisonBossLevel)Dungeon.level).state();
|
||||||
|
|
||||||
|
int hpBracket;
|
||||||
|
if (state == NewPrisonBossLevel.State.FIGHT_START){
|
||||||
|
hpBracket = 20;
|
||||||
|
} else {
|
||||||
|
hpBracket = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
int beforeHitHP = HP;
|
||||||
|
super.damage(dmg, src);
|
||||||
|
dmg = beforeHitHP - HP;
|
||||||
|
|
||||||
|
//tengu cannot be hit through multiple brackets at a time
|
||||||
|
if ((beforeHitHP/hpBracket - HP/hpBracket) >= 2){
|
||||||
|
HP = hpBracket * ((beforeHitHP/hpBracket)-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
|
||||||
|
if (lock != null) {
|
||||||
|
int multiple = state == NewPrisonBossLevel.State.FIGHT_START ? 1 : 4;
|
||||||
|
lock.addTime(dmg*multiple);
|
||||||
|
}
|
||||||
|
|
||||||
|
//phase 2 of the fight is over
|
||||||
|
if (HP == 0 && state == NewPrisonBossLevel.State.FIGHT_ARENA) {
|
||||||
|
//let full attack action complete first
|
||||||
|
Actor.add(new Actor() {
|
||||||
|
|
||||||
|
{
|
||||||
|
actPriority = VFX_PRIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean act() {
|
||||||
|
Actor.remove(this);
|
||||||
|
((NewPrisonBossLevel)Dungeon.level).progress();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//phase 1 of the fight is over
|
||||||
|
if (state == NewPrisonBossLevel.State.FIGHT_START && HP <= HT/2){
|
||||||
|
HP = (HT/2)-1;
|
||||||
|
yell(Messages.get(this, "interesting"));
|
||||||
|
((NewPrisonBossLevel)Dungeon.level).progress();
|
||||||
|
BossHealthBar.bleed(true);
|
||||||
|
|
||||||
|
//if tengu has lost a certain amount of hp, jump
|
||||||
|
} else if (beforeHitHP / hpBracket != HP / hpBracket) {
|
||||||
|
jump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAlive() {
|
||||||
|
return HP > 0 || Dungeon.level.mobs.contains(this); //Tengu has special death rules, see prisonbosslevel.progress()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void die( Object cause ) {
|
||||||
|
|
||||||
|
if (Dungeon.hero.subClass == HeroSubClass.NONE) {
|
||||||
|
Dungeon.level.drop( new TomeOfMastery(), pos ).sprite.drop();
|
||||||
|
}
|
||||||
|
|
||||||
|
GameScene.bossSlain();
|
||||||
|
super.die( cause );
|
||||||
|
|
||||||
|
Badges.validateBossSlain();
|
||||||
|
|
||||||
|
LloydsBeacon beacon = Dungeon.hero.belongings.getItem(LloydsBeacon.class);
|
||||||
|
if (beacon != null) {
|
||||||
|
beacon.upgrade();
|
||||||
|
}
|
||||||
|
|
||||||
|
yell( Messages.get(this, "defeated") );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canAttack( Char enemy ) {
|
||||||
|
return new Ballistica( pos, enemy.pos, Ballistica.PROJECTILE).collisionPos == enemy.pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
//tengu's attack is always visible
|
||||||
|
@Override
|
||||||
|
protected boolean doAttack(Char enemy) {
|
||||||
|
sprite.attack( enemy.pos );
|
||||||
|
spend( attackDelay() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void jump() {
|
||||||
|
|
||||||
|
//in case tengu hasn't had a chance to act yet
|
||||||
|
if (fieldOfView == null || fieldOfView.length != Dungeon.level.length()){
|
||||||
|
fieldOfView = new boolean[Dungeon.level.length()];
|
||||||
|
Dungeon.level.updateFieldOfView( this, fieldOfView );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (enemy == null) enemy = chooseEnemy();
|
||||||
|
if (enemy == null) return;
|
||||||
|
|
||||||
|
int newPos;
|
||||||
|
if (Dungeon.level instanceof NewPrisonBossLevel){
|
||||||
|
NewPrisonBossLevel level = (NewPrisonBossLevel) Dungeon.level;
|
||||||
|
|
||||||
|
//if we're in phase 1, want to warp around within the room
|
||||||
|
if (level.state() == NewPrisonBossLevel.State.FIGHT_START) {
|
||||||
|
|
||||||
|
level.cleanTenguCell();
|
||||||
|
|
||||||
|
do {
|
||||||
|
newPos = ((NewPrisonBossLevel)Dungeon.level).randomTenguCellPos();
|
||||||
|
} while ( (level.distance(newPos, enemy.pos) <= 2 || Actor.findChar(newPos) != null));
|
||||||
|
|
||||||
|
if (level.heroFOV[pos]) CellEmitter.get( pos ).burst( Speck.factory( Speck.WOOL ), 6 );
|
||||||
|
|
||||||
|
sprite.move( pos, newPos );
|
||||||
|
move( newPos );
|
||||||
|
|
||||||
|
if (level.heroFOV[newPos]) CellEmitter.get( newPos ).burst( Speck.factory( Speck.WOOL ), 6 );
|
||||||
|
Sample.INSTANCE.play( Assets.SND_PUFF );
|
||||||
|
|
||||||
|
spend( 1 / speed() );
|
||||||
|
|
||||||
|
float fill = 0.9f - 0.5f*((HP-80)/80f);
|
||||||
|
level.placeTrapsInTenguCell(fill);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
//otherwise.. TODO!
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
newPos = Random.Int(level.length());
|
||||||
|
} while (
|
||||||
|
level.solid[newPos] ||
|
||||||
|
level.distance(newPos, enemy.pos) < 6 ||
|
||||||
|
Actor.findChar(newPos) != null);
|
||||||
|
|
||||||
|
if (level.heroFOV[pos]) CellEmitter.get( pos ).burst( Speck.factory( Speck.WOOL ), 6 );
|
||||||
|
|
||||||
|
sprite.move( pos, newPos );
|
||||||
|
move( newPos );
|
||||||
|
|
||||||
|
if (level.heroFOV[newPos]) CellEmitter.get( newPos ).burst( Speck.factory( Speck.WOOL ), 6 );
|
||||||
|
Sample.INSTANCE.play( Assets.SND_PUFF );
|
||||||
|
|
||||||
|
spend( 1 / speed() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//if we're on another type of level
|
||||||
|
} else {
|
||||||
|
Level level = Dungeon.level;
|
||||||
|
|
||||||
|
newPos = level.randomRespawnCell();
|
||||||
|
|
||||||
|
if (level.heroFOV[pos]) CellEmitter.get( pos ).burst( Speck.factory( Speck.WOOL ), 6 );
|
||||||
|
|
||||||
|
sprite.move( pos, newPos );
|
||||||
|
move( newPos );
|
||||||
|
|
||||||
|
if (level.heroFOV[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();
|
||||||
|
if (!BossHealthBar.isAssigned()) {
|
||||||
|
BossHealthBar.assignBoss(this);
|
||||||
|
if (HP <= HT/2) BossHealthBar.bleed(true);
|
||||||
|
if (HP == HT) {
|
||||||
|
yell(Messages.get(this, "notice_mine", Dungeon.hero.givenName()));
|
||||||
|
for (Char ch : Actor.chars()){
|
||||||
|
if (ch instanceof DriedRose.GhostHero){
|
||||||
|
GLog.n("\n");
|
||||||
|
((DriedRose.GhostHero) ch).sayBoss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
yell(Messages.get(this, "notice_face", Dungeon.hero.givenName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreFromBundle(Bundle bundle) {
|
||||||
|
super.restoreFromBundle(bundle);
|
||||||
|
BossHealthBar.assignBoss(this);
|
||||||
|
if (HP <= HT/2) BossHealthBar.bleed(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//tengu is always hunting
|
||||||
|
private class Hunting extends Mob.Hunting{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean act(boolean enemyInFOV, boolean justAlerted) {
|
||||||
|
enemySeen = enemyInFOV;
|
||||||
|
if (enemyInFOV && !isCharmedBy( enemy ) && canAttack( enemy )) {
|
||||||
|
|
||||||
|
return doAttack( enemy );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (enemyInFOV) {
|
||||||
|
target = enemy.pos;
|
||||||
|
} else {
|
||||||
|
chooseEnemy();
|
||||||
|
if (enemy != null) {
|
||||||
|
target = enemy.pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spend( TICK );
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.DriedRose;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.LloydsBeacon;
|
import com.shatteredpixel.shatteredpixeldungeon.items.artifacts.LloydsBeacon;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfMagicMapping;
|
import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfMagicMapping;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonBossLevel;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.OldPrisonBossLevel;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.GrippingTrap;
|
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.GrippingTrap;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||||
|
@ -48,7 +48,8 @@ import com.watabou.noosa.audio.Sample;
|
||||||
import com.watabou.utils.Bundle;
|
import com.watabou.utils.Bundle;
|
||||||
import com.watabou.utils.Random;
|
import com.watabou.utils.Random;
|
||||||
|
|
||||||
public class Tengu extends Mob {
|
//Exists to support pre-0.7.5 saves
|
||||||
|
public class OldTengu extends Mob {
|
||||||
|
|
||||||
{
|
{
|
||||||
spriteClass = TenguSprite.class;
|
spriteClass = TenguSprite.class;
|
||||||
|
@ -89,10 +90,10 @@ public class Tengu extends Mob {
|
||||||
@Override
|
@Override
|
||||||
public void damage(int dmg, Object src) {
|
public void damage(int dmg, Object src) {
|
||||||
|
|
||||||
PrisonBossLevel.State state = ((PrisonBossLevel)Dungeon.level).state();
|
OldPrisonBossLevel.State state = ((OldPrisonBossLevel)Dungeon.level).state();
|
||||||
|
|
||||||
int hpBracket;
|
int hpBracket;
|
||||||
if (state == PrisonBossLevel.State.FIGHT_START){
|
if (state == OldPrisonBossLevel.State.FIGHT_START){
|
||||||
hpBracket = 12;
|
hpBracket = 12;
|
||||||
} else {
|
} else {
|
||||||
hpBracket = 20;
|
hpBracket = 20;
|
||||||
|
@ -104,12 +105,12 @@ public class Tengu extends Mob {
|
||||||
|
|
||||||
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
|
LockedFloor lock = Dungeon.hero.buff(LockedFloor.class);
|
||||||
if (lock != null) {
|
if (lock != null) {
|
||||||
int multiple = state == PrisonBossLevel.State.FIGHT_START ? 1 : 4;
|
int multiple = state == OldPrisonBossLevel.State.FIGHT_START ? 1 : 4;
|
||||||
lock.addTime(dmg*multiple);
|
lock.addTime(dmg*multiple);
|
||||||
}
|
}
|
||||||
|
|
||||||
//phase 2 of the fight is over
|
//phase 2 of the fight is over
|
||||||
if (HP == 0 && state == PrisonBossLevel.State.FIGHT_ARENA) {
|
if (HP == 0 && state == OldPrisonBossLevel.State.FIGHT_ARENA) {
|
||||||
//let full attack action complete first
|
//let full attack action complete first
|
||||||
Actor.add(new Actor() {
|
Actor.add(new Actor() {
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ public class Tengu extends Mob {
|
||||||
@Override
|
@Override
|
||||||
protected boolean act() {
|
protected boolean act() {
|
||||||
Actor.remove(this);
|
Actor.remove(this);
|
||||||
((PrisonBossLevel)Dungeon.level).progress();
|
((OldPrisonBossLevel)Dungeon.level).progress();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -128,10 +129,10 @@ public class Tengu extends Mob {
|
||||||
}
|
}
|
||||||
|
|
||||||
//phase 1 of the fight is over
|
//phase 1 of the fight is over
|
||||||
if (state == PrisonBossLevel.State.FIGHT_START && HP <= HT/2){
|
if (state == OldPrisonBossLevel.State.FIGHT_START && HP <= HT/2){
|
||||||
HP = (HT/2)-1;
|
HP = (HT/2)-1;
|
||||||
yell(Messages.get(this, "interesting"));
|
yell(Messages.get(this, "interesting"));
|
||||||
((PrisonBossLevel)Dungeon.level).progress();
|
((OldPrisonBossLevel)Dungeon.level).progress();
|
||||||
BossHealthBar.bleed(true);
|
BossHealthBar.bleed(true);
|
||||||
|
|
||||||
//if tengu has lost a certain amount of hp, jump
|
//if tengu has lost a certain amount of hp, jump
|
||||||
|
@ -193,7 +194,7 @@ public class Tengu extends Mob {
|
||||||
|
|
||||||
int newPos;
|
int newPos;
|
||||||
//if we're in phase 1, want to warp around within the room
|
//if we're in phase 1, want to warp around within the room
|
||||||
if (((PrisonBossLevel)Dungeon.level).state() == PrisonBossLevel.State.FIGHT_START) {
|
if (((OldPrisonBossLevel)Dungeon.level).state() == OldPrisonBossLevel.State.FIGHT_START) {
|
||||||
|
|
||||||
//place new traps
|
//place new traps
|
||||||
int tries;
|
int tries;
|
|
@ -0,0 +1,768 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 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.levels;
|
||||||
|
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.Bones;
|
||||||
|
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.mobs.Mob;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.NewTengu;
|
||||||
|
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.keys.IronKey;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.HeavyBoomerang;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Maze;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.TenguDartTrap;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.Trap;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.plants.Plant;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.tiles.CustomTilemap;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.tiles.DungeonTilemap;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ui.TargetHealthIndicator;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.utils.BArray;
|
||||||
|
import com.watabou.noosa.Camera;
|
||||||
|
import com.watabou.noosa.Group;
|
||||||
|
import com.watabou.noosa.Tilemap;
|
||||||
|
import com.watabou.noosa.audio.Sample;
|
||||||
|
import com.watabou.noosa.tweeners.AlphaTweener;
|
||||||
|
import com.watabou.utils.Bundlable;
|
||||||
|
import com.watabou.utils.Bundle;
|
||||||
|
import com.watabou.utils.PathFinder;
|
||||||
|
import com.watabou.utils.Point;
|
||||||
|
import com.watabou.utils.Random;
|
||||||
|
import com.watabou.utils.Rect;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class NewPrisonBossLevel extends Level {
|
||||||
|
|
||||||
|
{
|
||||||
|
color1 = 0x6a723d;
|
||||||
|
color2 = 0x88924c;
|
||||||
|
|
||||||
|
//the player should be able to see all of Tengu's arena
|
||||||
|
viewDistance = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
START,
|
||||||
|
FIGHT_START,
|
||||||
|
TRAP_MAZES,
|
||||||
|
FIGHT_ARENA,
|
||||||
|
WON
|
||||||
|
}
|
||||||
|
|
||||||
|
private State state;
|
||||||
|
private NewTengu tengu;
|
||||||
|
|
||||||
|
public State state(){
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String tilesTex() {
|
||||||
|
return Assets.TILES_PRISON;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String waterTex() {
|
||||||
|
return Assets.WATER_PRISON;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String STATE = "state";
|
||||||
|
private static final String TENGU = "tengu";
|
||||||
|
private static final String STORED_ITEMS = "storeditems";
|
||||||
|
private static final String TRIGGERED = "triggered";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void storeInBundle( Bundle bundle ) {
|
||||||
|
super.storeInBundle(bundle);
|
||||||
|
bundle.put( STATE, state );
|
||||||
|
bundle.put( TENGU, tengu );
|
||||||
|
bundle.put( STORED_ITEMS, storedItems);
|
||||||
|
bundle.put(TRIGGERED, triggered );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void restoreFromBundle( Bundle bundle ) {
|
||||||
|
super.restoreFromBundle(bundle);
|
||||||
|
state = bundle.getEnum( STATE, State.class );
|
||||||
|
|
||||||
|
//in some states tengu won't be in the world, in others he will be.
|
||||||
|
if (state == State.START || state == State.TRAP_MAZES) {
|
||||||
|
tengu = (NewTengu)bundle.get( TENGU );
|
||||||
|
} else {
|
||||||
|
for (Mob mob : mobs){
|
||||||
|
if (mob instanceof NewTengu) {
|
||||||
|
tengu = (NewTengu) mob;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Bundlable item : bundle.getCollection(STORED_ITEMS)){
|
||||||
|
storedItems.add( (Item)item );
|
||||||
|
}
|
||||||
|
|
||||||
|
triggered = bundle.getBooleanArray(TRIGGERED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean build() {
|
||||||
|
setSize(32, 32);
|
||||||
|
|
||||||
|
state = State.START;
|
||||||
|
setMapStart();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int ENTRANCE_POS = 10 + 4*32;
|
||||||
|
private static final Rect entranceRoom = new Rect(8, 2, 13, 8);
|
||||||
|
private static final Rect startHallway = new Rect(9, 7, 12, 24);
|
||||||
|
private static final Rect[] startCells = new Rect[]{ new Rect(5, 9, 10, 16), new Rect(11, 9, 16, 16),
|
||||||
|
new Rect(5, 15, 10, 22), new Rect(11, 15, 16, 22)};
|
||||||
|
private static final Rect tenguCell = new Rect(6, 23, 15, 32);
|
||||||
|
private static final Point tenguCellCenter = new Point(10, 27);
|
||||||
|
private static final Point tenguCellDoor = new Point(10, 23);
|
||||||
|
private static final Point[] startTorches = new Point[]{ new Point(10, 2),
|
||||||
|
new Point(7, 9), new Point(13, 9),
|
||||||
|
new Point(7, 15), new Point(13, 15),
|
||||||
|
new Point(8, 23), new Point(12, 23)};
|
||||||
|
|
||||||
|
private void setMapStart(){
|
||||||
|
entrance = ENTRANCE_POS;
|
||||||
|
exit = 0;
|
||||||
|
|
||||||
|
Painter.fill(this, 0, 0, 32, 32, Terrain.WALL);
|
||||||
|
|
||||||
|
//Start
|
||||||
|
Painter.fill(this, entranceRoom, Terrain.WALL);
|
||||||
|
Painter.fill(this, entranceRoom, 1, Terrain.EMPTY);
|
||||||
|
Painter.set(this, entrance, Terrain.ENTRANCE);
|
||||||
|
|
||||||
|
Painter.fill(this, startHallway, Terrain.WALL);
|
||||||
|
Painter.fill(this, startHallway, 1, Terrain.EMPTY);
|
||||||
|
|
||||||
|
Painter.set(this, startHallway.left+1, startHallway.top, Terrain.DOOR);
|
||||||
|
|
||||||
|
for (Rect r : startCells){
|
||||||
|
Painter.fill(this, r, Terrain.WALL);
|
||||||
|
Painter.fill(this, r, 1, Terrain.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
Painter.set(this, startHallway.left, startHallway.top+5, Terrain.DOOR);
|
||||||
|
Painter.set(this, startHallway.right-1, startHallway.top+5, Terrain.DOOR);
|
||||||
|
Painter.set(this, startHallway.left, startHallway.top+11, Terrain.DOOR);
|
||||||
|
Painter.set(this, startHallway.right-1, startHallway.top+11, Terrain.DOOR);
|
||||||
|
|
||||||
|
Painter.fill(this, tenguCell, Terrain.WALL);
|
||||||
|
Painter.fill(this, tenguCell, 1, Terrain.EMPTY);
|
||||||
|
|
||||||
|
Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.LOCKED_DOOR);
|
||||||
|
|
||||||
|
drop(new IronKey(10), randomPrisonCellPos());
|
||||||
|
|
||||||
|
for (Point p : startTorches){
|
||||||
|
Painter.set(this, p, Terrain.WALL_DECO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Rect mazeHallway = new Rect(9, 6, 12, 24);
|
||||||
|
private static final Rect[] mazeCells = new Rect[]{ new Rect(1, 9, 10, 16), new Rect(11, 9, 20, 16),
|
||||||
|
new Rect(3, 15, 10, 22), new Rect(11, 15, 18, 22)};
|
||||||
|
private static final Point[] mazeKeySpawns = new Point[]{new Point(mazeCells[0].left+1, mazeCells[0].top+3),
|
||||||
|
new Point(mazeCells[1].right-2, mazeCells[1].top+3),
|
||||||
|
new Point(mazeCells[2].left+1, mazeCells[2].top+3),
|
||||||
|
new Point(mazeCells[3].right-2, mazeCells[3].top+3)};
|
||||||
|
private static final Point[] mazeCellDoors = new Point[]{new Point(mazeCells[0].right-1, mazeCells[0].top+3),
|
||||||
|
new Point(mazeCells[1].left, mazeCells[1].top+3),
|
||||||
|
new Point(mazeCells[2].right-1, mazeCells[2].top+3),
|
||||||
|
new Point(mazeCells[3].left, mazeCells[3].top+3)};
|
||||||
|
private static final Point[] mazeTorches = new Point[]{ new Point(5, 9), new Point(15, 9),
|
||||||
|
new Point(6, 15), new Point(14, 15),
|
||||||
|
new Point(8, 23), new Point(12, 23)};
|
||||||
|
|
||||||
|
private void setMapMazes(){
|
||||||
|
exit = entrance = 0;
|
||||||
|
|
||||||
|
Painter.fill(this, 0, 0, 32, 32, Terrain.WALL);
|
||||||
|
|
||||||
|
Painter.fill(this, mazeHallway, Terrain.WALL);
|
||||||
|
Painter.fill(this, mazeHallway, 1, Terrain.EMPTY);
|
||||||
|
|
||||||
|
for (Rect r : mazeCells){
|
||||||
|
Painter.fill(this, r, Terrain.WALL);
|
||||||
|
Painter.fill(this, r, 1, Terrain.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Point p : mazeCellDoors){
|
||||||
|
Painter.set(this, p, Terrain.DOOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
Painter.fill(this, tenguCell, Terrain.WALL);
|
||||||
|
Painter.fill(this, tenguCell, 1, Terrain.EMPTY);
|
||||||
|
|
||||||
|
Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.DOOR);
|
||||||
|
|
||||||
|
Painter.set(this, mazeHallway.left+1, mazeHallway.top+2, Terrain.LOCKED_DOOR);
|
||||||
|
Painter.set(this, mazeHallway.left+1, mazeHallway.top+4, Terrain.LOCKED_DOOR);
|
||||||
|
Painter.set(this, mazeHallway.left+1, mazeHallway.top+8, Terrain.LOCKED_DOOR);
|
||||||
|
Painter.set(this, mazeHallway.left+1, mazeHallway.top+10, Terrain.LOCKED_DOOR);
|
||||||
|
|
||||||
|
for (Point p : mazeKeySpawns){
|
||||||
|
drop(new IronKey(10), pointToCell(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Point p : mazeTorches){
|
||||||
|
Painter.set(this, p, Terrain.WALL_DECO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Rect arena = new Rect(3, 1, 18, 16);
|
||||||
|
|
||||||
|
private void setMapArena(){
|
||||||
|
exit = entrance = 0;
|
||||||
|
|
||||||
|
Painter.fill(this, 0, 0, 32, 32, Terrain.WALL);
|
||||||
|
|
||||||
|
Painter.fill(this, arena, Terrain.WALL);
|
||||||
|
Painter.fillEllipse(this, arena, 1, Terrain.EMPTY);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int W = Terrain.WALL;
|
||||||
|
private static int D = Terrain.WALL_DECO;
|
||||||
|
private static int e = Terrain.EMPTY;
|
||||||
|
private static int C = Terrain.CHASM;
|
||||||
|
|
||||||
|
private static final Point endStart = new Point( startHallway.left+2, startHallway.top+2);
|
||||||
|
private static final Point levelExit = new Point( endStart.x+12, endStart.y+8);
|
||||||
|
private static final int[] endMap = new int[]{
|
||||||
|
W, W, W, W, W, W, W, W, W, W, W, W, W, W,
|
||||||
|
W, e, e, e, W, W, W, W, W, W, W, W, W, W,
|
||||||
|
W, e, e, e, e, e, e, e, e, W, W, W, W, W,
|
||||||
|
e, e, e, e, e, e, e, e, e, e, e, e, W, W,
|
||||||
|
e, e, e, e, e, e, e, e, e, e, e, e, e, W,
|
||||||
|
e, e, e, e, C, C, C, C, C, C, e, e, e, W,
|
||||||
|
e, W, C, C, C, C, C, C, C, C, C, e, e, W,
|
||||||
|
e, e, e, e, C, C, C, C, C, C, C, C, e, W,
|
||||||
|
e, e, e, e, e, e, e, C, C, C, C, C, e, W,
|
||||||
|
e, e, e, e, e, e, e, W, W, W, C, C, C, W,
|
||||||
|
e, e, e, e, e, e, W, W, W, W, C, C, C, W,
|
||||||
|
W, e, e, e, e, W, W, W, W, W, W, C, C, W,
|
||||||
|
W, W, W, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
W, W, W, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
W, D, W, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
e, e, e, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
e, e, e, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
e, e, e, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
e, e, e, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
e, e, e, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
e, e, e, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
e, e, e, W, W, W, W, W, W, W, W, C, C, W,
|
||||||
|
W, W, W, W, W, W, W, W, W, W, W, C, C, W
|
||||||
|
};
|
||||||
|
|
||||||
|
private void setMapEnd(){
|
||||||
|
|
||||||
|
Painter.fill(this, 0, 0, 32, 32, Terrain.WALL);
|
||||||
|
|
||||||
|
setMapStart();
|
||||||
|
|
||||||
|
for (Heap h : heaps.valueList()){
|
||||||
|
if (h.peek() instanceof IronKey){
|
||||||
|
h.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Painter.set(this, tenguCell.left+4, tenguCell.top, Terrain.DOOR);
|
||||||
|
|
||||||
|
int cell = pointToCell(endStart);
|
||||||
|
int i = 0;
|
||||||
|
while (cell < length()){
|
||||||
|
System.arraycopy(endMap, i, map, cell, 14);
|
||||||
|
i += 14;
|
||||||
|
cell += width();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit = pointToCell(levelExit);
|
||||||
|
Painter.set(this, exit, Terrain.EXIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
//keep track of removed items as the level is changed. Dump them back into the level at the end.
|
||||||
|
private ArrayList<Item> storedItems = new ArrayList<>();
|
||||||
|
|
||||||
|
private void clearEntities(Rect safeArea){
|
||||||
|
for (Heap heap : heaps.valueList()){
|
||||||
|
if (safeArea == null || !safeArea.inside(cellToPoint(heap.pos))){
|
||||||
|
storedItems.addAll(heap.items);
|
||||||
|
heap.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (HeavyBoomerang.CircleBack b : Dungeon.hero.buffs(HeavyBoomerang.CircleBack.class)){
|
||||||
|
if (safeArea == null || !safeArea.inside(cellToPoint(b.returnPos()))){
|
||||||
|
storedItems.add(b.cancel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Mob mob : Dungeon.level.mobs.toArray(new Mob[0])){
|
||||||
|
if (mob != tengu && (safeArea == null || !safeArea.inside(cellToPoint(mob.pos)))){
|
||||||
|
mob.destroy();
|
||||||
|
if (mob.sprite != null)
|
||||||
|
mob.sprite.killAndErase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (Plant plant : plants.valueList()){
|
||||||
|
if (safeArea == null || !safeArea.inside(cellToPoint(plant.pos))){
|
||||||
|
plants.remove(plant.pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanMapState(){
|
||||||
|
buildFlagMaps();
|
||||||
|
cleanWalls();
|
||||||
|
|
||||||
|
BArray.setFalse(visited);
|
||||||
|
BArray.setFalse(mapped);
|
||||||
|
|
||||||
|
for (Blob blob: blobs.values()){
|
||||||
|
blob.fullyClear();
|
||||||
|
}
|
||||||
|
addVisuals(); //this also resets existing visuals
|
||||||
|
traps.clear();
|
||||||
|
|
||||||
|
GameScene.resetMap();
|
||||||
|
Dungeon.observe();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Group addVisuals() {
|
||||||
|
super.addVisuals();
|
||||||
|
PrisonLevel.addPrisonVisuals(this, visuals);
|
||||||
|
return visuals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void progress(){
|
||||||
|
switch (state){
|
||||||
|
case START:
|
||||||
|
|
||||||
|
//if something is occupying Tengu's space, wait and do nothing.
|
||||||
|
if (Actor.findChar(pointToCell(tenguCellCenter)) != null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
seal();
|
||||||
|
set(pointToCell(tenguCellDoor), Terrain.LOCKED_DOOR);
|
||||||
|
GameScene.updateMap(pointToCell(tenguCellDoor));
|
||||||
|
|
||||||
|
for (Mob m : mobs){
|
||||||
|
//bring the first ally with you
|
||||||
|
if (m.alignment == Char.Alignment.ALLY && !m.properties().contains(Char.Property.IMMOVABLE)){
|
||||||
|
m.pos = pointToCell(tenguCellDoor); //they should immediately walk out of the door
|
||||||
|
m.sprite.place(m.pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tengu.state = tengu.HUNTING;
|
||||||
|
tengu.pos = pointToCell(tenguCellCenter); //in the middle of the fight room
|
||||||
|
GameScene.add( tengu );
|
||||||
|
tengu.notice();
|
||||||
|
|
||||||
|
state = State.FIGHT_START;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIGHT_START:
|
||||||
|
|
||||||
|
clearEntities( tenguCell ); //clear anything not in tengu's cell
|
||||||
|
|
||||||
|
Actor.remove(tengu);
|
||||||
|
mobs.remove(tengu);
|
||||||
|
TargetHealthIndicator.instance.target(null);
|
||||||
|
tengu.sprite.kill();
|
||||||
|
|
||||||
|
setMapMazes();
|
||||||
|
cleanMapState();
|
||||||
|
|
||||||
|
GameScene.flash(0xFFFFFF);
|
||||||
|
Sample.INSTANCE.play(Assets.SND_BLAST);
|
||||||
|
|
||||||
|
state = State.TRAP_MAZES;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TRAP_MAZES:
|
||||||
|
|
||||||
|
Dungeon.hero.interrupt();
|
||||||
|
|
||||||
|
clearEntities( arena ); //clear anything not in the arena
|
||||||
|
|
||||||
|
setMapArena();
|
||||||
|
cleanMapState();
|
||||||
|
|
||||||
|
tengu.state = tengu.HUNTING;
|
||||||
|
do {
|
||||||
|
tengu.pos = Random.Int(length());
|
||||||
|
} while (solid[tengu.pos] || distance(tengu.pos, Dungeon.hero.pos) < 6);
|
||||||
|
GameScene.add(tengu);
|
||||||
|
tengu.notice();
|
||||||
|
|
||||||
|
GameScene.flash(0xFFFFFF);
|
||||||
|
Sample.INSTANCE.play(Assets.SND_BLAST);
|
||||||
|
|
||||||
|
state = State.FIGHT_ARENA;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FIGHT_ARENA:
|
||||||
|
|
||||||
|
unseal();
|
||||||
|
|
||||||
|
CustomTilemap vis = new exitVisual();
|
||||||
|
vis.pos(11, 9);
|
||||||
|
customTiles.add(vis);
|
||||||
|
GameScene.add(vis, false);
|
||||||
|
|
||||||
|
vis = new exitVisualWalls();
|
||||||
|
vis.pos(12, 9);
|
||||||
|
customWalls.add(vis);
|
||||||
|
GameScene.add(vis, true);
|
||||||
|
|
||||||
|
Dungeon.hero.interrupt();
|
||||||
|
Dungeon.hero.pos = tenguCell.left+4 + (tenguCell.top+2)*width();
|
||||||
|
Dungeon.hero.sprite.interruptMotion();
|
||||||
|
Dungeon.hero.sprite.place(Dungeon.hero.pos);
|
||||||
|
Camera.main.snapTo(Dungeon.hero.sprite.center());
|
||||||
|
|
||||||
|
tengu.pos = pointToCell(tenguCellCenter);
|
||||||
|
tengu.sprite.place(tengu.pos);
|
||||||
|
|
||||||
|
//remove all mobs, but preserve allies
|
||||||
|
ArrayList<Mob> allies = new ArrayList<>();
|
||||||
|
for(Mob m : mobs.toArray(new Mob[0])){
|
||||||
|
if (m.alignment == Char.Alignment.ALLY && !m.properties().contains(Char.Property.IMMOVABLE)){
|
||||||
|
allies.add(m);
|
||||||
|
mobs.remove(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setMapEnd();
|
||||||
|
cleanMapState();
|
||||||
|
|
||||||
|
for (Mob m : allies){
|
||||||
|
do{
|
||||||
|
m.pos = randomTenguCellPos();
|
||||||
|
} while (findMob(m.pos) != null);
|
||||||
|
if (m.sprite != null) m.sprite.place(m.pos);
|
||||||
|
mobs.add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
tengu.die(Dungeon.hero);
|
||||||
|
|
||||||
|
clearEntities(tenguCell);
|
||||||
|
|
||||||
|
for (Item item : storedItems) {
|
||||||
|
drop(item, randomTenguCellPos());
|
||||||
|
}
|
||||||
|
|
||||||
|
GameScene.flash(0xFFFFFF);
|
||||||
|
Sample.INSTANCE.play(Assets.SND_BLAST);
|
||||||
|
|
||||||
|
state = State.WON;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean[] triggered = new boolean[]{false, false, false, false};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void occupyCell(Char ch) {
|
||||||
|
super.occupyCell(ch);
|
||||||
|
|
||||||
|
if (ch == Dungeon.hero){
|
||||||
|
switch (state){
|
||||||
|
case START:
|
||||||
|
if (cellToPoint(ch.pos).y > tenguCell.top){
|
||||||
|
progress();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TRAP_MAZES:
|
||||||
|
|
||||||
|
for (int i = 0; i < mazeCellDoors.length; i++){
|
||||||
|
if (ch.pos == pointToCell(mazeCellDoors[i]) && !triggered[i]){
|
||||||
|
triggered[i] = true;
|
||||||
|
Maze.allowDiagonals = true;
|
||||||
|
boolean[][] maze = Maze.generate(mazeCells[i], map, width(), Terrain.WALL);
|
||||||
|
|
||||||
|
for (int x = 1; x < maze.length-1; x++) {
|
||||||
|
for (int y = 1; y < maze[0].length-1; y++) {
|
||||||
|
if (maze[x][y] && !(x == 1 && y == 3)){
|
||||||
|
int cell = mazeCells[i].left+x + width()*(mazeCells[i].top+y);
|
||||||
|
if (heaps.get(cell) == null){
|
||||||
|
setTrap(new TenguDartTrap().hide(), cell);
|
||||||
|
Painter.set(this, cell, Terrain.SECRET_TRAP);
|
||||||
|
CellEmitter.get(cell).burst(Speck.factory(Speck.LIGHT), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FadingTraps f = new FadingTraps();
|
||||||
|
f.setCoveringArea(mazeCells[i]);
|
||||||
|
GameScene.add(f, false);
|
||||||
|
f.startFade(2.5f);
|
||||||
|
|
||||||
|
Sample.INSTANCE.play(Assets.SND_TELEPORT);
|
||||||
|
int roomCenter = (mazeCells[i].left + mazeCells[i].right)/2 +
|
||||||
|
(mazeCells[i].top + mazeCells[i].bottom)/2 * width();
|
||||||
|
Camera.main.panTo(DungeonTilemap.tileCenterToWorld(roomCenter), 5f);
|
||||||
|
|
||||||
|
Dungeon.hero.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cellToPoint(ch.pos).y <= mazeHallway.top+2){
|
||||||
|
progress();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createMobs() {
|
||||||
|
tengu = new NewTengu(); //We want to keep track of tengu independently of other mobs, he's not always in the level.
|
||||||
|
}
|
||||||
|
|
||||||
|
public Actor respawner() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createItems() {
|
||||||
|
Item item = Bones.get();
|
||||||
|
if (item != null) {
|
||||||
|
drop( item, randomRespawnCell() ).setHauntedIfCursed(1f).type = Heap.Type.REMAINS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int randomPrisonCellPos(){
|
||||||
|
Rect room = startCells[Random.Int(startCells.length)];
|
||||||
|
|
||||||
|
return Random.IntRange(room.left+1, room.right-2)
|
||||||
|
+ width()*Random.IntRange(room.top+1, room.bottom-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int randomTenguCellPos(){
|
||||||
|
return Random.IntRange(tenguCell.left+1, tenguCell.right-2)
|
||||||
|
+ width()*Random.IntRange(tenguCell.top+1, tenguCell.bottom-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanTenguCell(){
|
||||||
|
|
||||||
|
traps.clear();
|
||||||
|
Painter.fill(this, tenguCell, 1, Terrain.EMPTY);
|
||||||
|
buildFlagMaps();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void placeTrapsInTenguCell(float fill){
|
||||||
|
|
||||||
|
Point tenguPoint = cellToPoint(tengu.pos);
|
||||||
|
Point heroPoint = cellToPoint(Dungeon.hero.pos);
|
||||||
|
|
||||||
|
PathFinder.setMapSize(7, 7);
|
||||||
|
|
||||||
|
int tenguPos = tenguPoint.x-(tenguCell.left+1) + (tenguPoint.y-(tenguCell.top+1))*7;
|
||||||
|
int heroPos = heroPoint.x-(tenguCell.left+1) + (heroPoint.y-(tenguCell.top+1))*7;
|
||||||
|
|
||||||
|
boolean[] trapsPatch;
|
||||||
|
|
||||||
|
do {
|
||||||
|
trapsPatch = Patch.generate(7, 7, fill, 0, false);
|
||||||
|
|
||||||
|
PathFinder.buildDistanceMap(tenguPos, BArray.not(trapsPatch, null));
|
||||||
|
} while (PathFinder.distance[heroPos] > 6);
|
||||||
|
|
||||||
|
PathFinder.setMapSize(width(), height());
|
||||||
|
|
||||||
|
for (int i = 0; i < trapsPatch.length; i++){
|
||||||
|
if (trapsPatch[i]) {
|
||||||
|
int x = i % 7;
|
||||||
|
int y = i / 7;
|
||||||
|
int cell = x+tenguCell.left+1 + (y+tenguCell.top+1)*width();
|
||||||
|
Level.set(cell, Terrain.SECRET_TRAP);
|
||||||
|
setTrap(new TenguDartTrap().hide(), cell);
|
||||||
|
CellEmitter.get(cell).burst(Speck.factory(Speck.LIGHT), 2);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameScene.updateMap();
|
||||||
|
|
||||||
|
FadingTraps t = new FadingTraps();
|
||||||
|
t.setCoveringArea(tenguCell);
|
||||||
|
GameScene.add(t, false);
|
||||||
|
t.startFade( 2.5f );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int randomRespawnCell() {
|
||||||
|
int pos = ENTRANCE_POS; //random cell adjacent to the entrance.
|
||||||
|
int cell;
|
||||||
|
do {
|
||||||
|
cell = pos + PathFinder.NEIGHBOURS8[Random.Int(8)];
|
||||||
|
} while (!passable[cell] || Actor.findChar(cell) != null);
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String tileName( int tile ) {
|
||||||
|
switch (tile) {
|
||||||
|
case Terrain.WATER:
|
||||||
|
return Messages.get(PrisonLevel.class, "water_name");
|
||||||
|
default:
|
||||||
|
return super.tileName( tile );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String tileDesc(int tile) {
|
||||||
|
switch (tile) {
|
||||||
|
case Terrain.EMPTY_DECO:
|
||||||
|
return Messages.get(PrisonLevel.class, "empty_deco_desc");
|
||||||
|
case Terrain.BOOKSHELF:
|
||||||
|
return Messages.get(PrisonLevel.class, "bookshelf_desc");
|
||||||
|
default:
|
||||||
|
return super.tileDesc( tile );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FadingTraps extends CustomTilemap {
|
||||||
|
|
||||||
|
{
|
||||||
|
texture = Assets.TERRAIN_FEATURES;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect area;
|
||||||
|
|
||||||
|
public void setCoveringArea(Rect area){
|
||||||
|
tileX = area.left;
|
||||||
|
tileY = area.top;
|
||||||
|
tileH = area.bottom - area.top;
|
||||||
|
tileW = area.right - area.left;
|
||||||
|
|
||||||
|
this.area = area;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tilemap create() {
|
||||||
|
Tilemap v = super.create();
|
||||||
|
int[] data = new int[tileW*tileH];
|
||||||
|
int cell;
|
||||||
|
Trap t;
|
||||||
|
int i = 0;
|
||||||
|
for (int y = tileY; y < tileY + tileH; y++){
|
||||||
|
cell = tileX + y*width();
|
||||||
|
for (int x = tileX; x < tileX + tileW; x++){
|
||||||
|
t = traps.get(cell);
|
||||||
|
if (t != null){
|
||||||
|
data[i] = t.color + t.shape*16;
|
||||||
|
} else {
|
||||||
|
data[i] = -1;
|
||||||
|
}
|
||||||
|
cell++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v.map( data, tileW );
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startFade( float duration ){
|
||||||
|
if (vis == null || vis.parent == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vis.parent.add(new AlphaTweener(vis, 0f, duration){
|
||||||
|
@Override
|
||||||
|
protected void onComplete() {
|
||||||
|
super.onComplete();
|
||||||
|
vis.killAndErase();
|
||||||
|
killAndErase();
|
||||||
|
vis = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class exitVisual extends CustomTilemap {
|
||||||
|
|
||||||
|
{
|
||||||
|
texture = Assets.PRISON_EXIT_NEW;
|
||||||
|
|
||||||
|
tileW = 13;
|
||||||
|
tileH = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int TEX_WIDTH = 512;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tilemap create() {
|
||||||
|
Tilemap v = super.create();
|
||||||
|
v.map(mapSimpleImage(0, 0, TEX_WIDTH), tileW);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class exitVisualWalls extends CustomTilemap {
|
||||||
|
|
||||||
|
{
|
||||||
|
texture = Assets.PRISON_EXIT_NEW;
|
||||||
|
|
||||||
|
tileW = 13;
|
||||||
|
tileH = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int TEX_WIDTH = 512;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tilemap create() {
|
||||||
|
Tilemap v = super.create();
|
||||||
|
v.map(mapSimpleImage(13, 0, TEX_WIDTH), tileW);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -29,7 +29,7 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.Blob;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Tengu;
|
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.OldTengu;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
|
||||||
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
|
import com.shatteredpixel.shatteredpixeldungeon.items.keys.IronKey;
|
||||||
|
@ -55,7 +55,8 @@ import com.watabou.utils.Random;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class PrisonBossLevel extends Level {
|
//Exists to support pre-0.7.5 saves
|
||||||
|
public class OldPrisonBossLevel extends Level {
|
||||||
|
|
||||||
{
|
{
|
||||||
color1 = 0x6a723d;
|
color1 = 0x6a723d;
|
||||||
|
@ -74,7 +75,7 @@ public class PrisonBossLevel extends Level {
|
||||||
private static final int ARENA_DOOR = 5+25*32;
|
private static final int ARENA_DOOR = 5+25*32;
|
||||||
|
|
||||||
private State state;
|
private State state;
|
||||||
private Tengu tengu;
|
private OldTengu tengu;
|
||||||
|
|
||||||
public State state(){
|
public State state(){
|
||||||
return state;
|
return state;
|
||||||
|
@ -112,11 +113,11 @@ public class PrisonBossLevel extends Level {
|
||||||
|
|
||||||
//in some states tengu won't be in the world, in others he will be.
|
//in some states tengu won't be in the world, in others he will be.
|
||||||
if (state == State.START || state == State.MAZE) {
|
if (state == State.START || state == State.MAZE) {
|
||||||
tengu = (Tengu)bundle.get( TENGU );
|
tengu = (OldTengu)bundle.get( TENGU );
|
||||||
} else {
|
} else {
|
||||||
for (Mob mob : mobs){
|
for (Mob mob : mobs){
|
||||||
if (mob instanceof Tengu) {
|
if (mob instanceof OldTengu) {
|
||||||
tengu = (Tengu) mob;
|
tengu = (OldTengu) mob;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,7 +149,7 @@ public class PrisonBossLevel extends Level {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createMobs() {
|
protected void createMobs() {
|
||||||
tengu = new Tengu(); //We want to keep track of tengu independently of other mobs, he's not always in the level.
|
tengu = new OldTengu(); //We want to keep track of tengu independently of other mobs, he's not always in the level.
|
||||||
}
|
}
|
||||||
|
|
||||||
public Actor respawner() {
|
public Actor respawner() {
|
||||||
|
@ -280,7 +281,7 @@ public class PrisonBossLevel extends Level {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearEntities(Room safeArea){
|
private void clearEntities(Room safeArea){
|
||||||
for (Heap heap : heaps.values()){
|
for (Heap heap : heaps.valueList()){
|
||||||
if (safeArea == null || !safeArea.inside(cellToPoint(heap.pos))){
|
if (safeArea == null || !safeArea.inside(cellToPoint(heap.pos))){
|
||||||
storedItems.addAll(heap.items);
|
storedItems.addAll(heap.items);
|
||||||
heap.destroy();
|
heap.destroy();
|
||||||
|
@ -300,7 +301,7 @@ public class PrisonBossLevel extends Level {
|
||||||
mob.sprite.killAndErase();
|
mob.sprite.killAndErase();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Plant plant : plants.values()){
|
for (Plant plant : plants.valueList()){
|
||||||
if (safeArea == null || !safeArea.inside(cellToPoint(plant.pos))){
|
if (safeArea == null || !safeArea.inside(cellToPoint(plant.pos))){
|
||||||
plants.remove(plant.pos);
|
plants.remove(plant.pos);
|
||||||
}
|
}
|
||||||
|
@ -613,7 +614,7 @@ public class PrisonBossLevel extends Level {
|
||||||
public static class exitVisual extends CustomTilemap {
|
public static class exitVisual extends CustomTilemap {
|
||||||
|
|
||||||
{
|
{
|
||||||
texture = Assets.PRISON_EXIT;
|
texture = Assets.PRISON_EXIT_OLD;
|
||||||
|
|
||||||
tileW = 12;
|
tileW = 12;
|
||||||
tileH = 14;
|
tileH = 14;
|
||||||
|
@ -656,7 +657,7 @@ public class PrisonBossLevel extends Level {
|
||||||
public static class exitVisualWalls extends CustomTilemap {
|
public static class exitVisualWalls extends CustomTilemap {
|
||||||
|
|
||||||
{
|
{
|
||||||
texture = Assets.PRISON_EXIT;
|
texture = Assets.PRISON_EXIT_OLD;
|
||||||
|
|
||||||
tileW = 12;
|
tileW = 12;
|
||||||
tileH = 14;
|
tileH = 14;
|
|
@ -48,15 +48,23 @@ public class PoisonDartTrap extends Trap {
|
||||||
return 8 + Math.round(2*Dungeon.depth / 3f);
|
return 8 + Math.round(2*Dungeon.depth / 3f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean canTarget( Char ch ){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void activate() {
|
public void activate() {
|
||||||
Char target = Actor.findChar(pos);
|
Char target = Actor.findChar(pos);
|
||||||
|
|
||||||
|
if (target != null && !canTarget(target)){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
//find the closest char that can be aimed at
|
//find the closest char that can be aimed at
|
||||||
if (target == null){
|
if (target == null){
|
||||||
for (Char ch : Actor.chars()){
|
for (Char ch : Actor.chars()){
|
||||||
Ballistica bolt = new Ballistica(pos, ch.pos, Ballistica.PROJECTILE);
|
Ballistica bolt = new Ballistica(pos, ch.pos, Ballistica.PROJECTILE);
|
||||||
if (bolt.collisionPos == ch.pos &&
|
if (canTarget(ch) && bolt.collisionPos == ch.pos &&
|
||||||
(target == null || Dungeon.level.trueDistance(pos, ch.pos) < Dungeon.level.trueDistance(pos, target.pos))){
|
(target == null || Dungeon.level.trueDistance(pos, ch.pos) < Dungeon.level.trueDistance(pos, target.pos))){
|
||||||
target = ch;
|
target = ch;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Pixel Dungeon
|
||||||
|
* Copyright (C) 2012-2015 Oleg Dolya
|
||||||
|
*
|
||||||
|
* Shattered Pixel Dungeon
|
||||||
|
* Copyright (C) 2014-2019 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.levels.traps;
|
||||||
|
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.NewTengu;
|
||||||
|
|
||||||
|
public class TenguDartTrap extends PoisonDartTrap {
|
||||||
|
|
||||||
|
{
|
||||||
|
canBeHidden = true;
|
||||||
|
canBeSearched = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int poisonAmount() {
|
||||||
|
return 9; //21 damage total
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canTarget(Char ch) {
|
||||||
|
return !(ch instanceof NewTengu);
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,10 @@ public final class ShadowCaster {
|
||||||
|
|
||||||
public static void castShadow( int x, int y, boolean[] fieldOfView, boolean[] blocking, int distance ) {
|
public static void castShadow( int x, int y, boolean[] fieldOfView, boolean[] blocking, int distance ) {
|
||||||
|
|
||||||
|
if (distance >= MAX_DISTANCE){
|
||||||
|
distance = MAX_DISTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
BArray.setFalse(fieldOfView);
|
BArray.setFalse(fieldOfView);
|
||||||
|
|
||||||
//set source cell to true
|
//set source cell to true
|
||||||
|
|
|
@ -582,13 +582,21 @@ actors.mobs.swarm.name=swarm of flies
|
||||||
actors.mobs.swarm.def_verb=evaded
|
actors.mobs.swarm.def_verb=evaded
|
||||||
actors.mobs.swarm.desc=The deadly swarm of flies buzzes angrily. Every non-magical attack will split it into two smaller but equally dangerous swarms.
|
actors.mobs.swarm.desc=The deadly swarm of flies buzzes angrily. Every non-magical attack will split it into two smaller but equally dangerous swarms.
|
||||||
|
|
||||||
actors.mobs.tengu.name=Tengu
|
actors.mobs.newtengu.name=Tengu
|
||||||
actors.mobs.tengu.notice_mine=You're mine, %s!
|
actors.mobs.newtengu.notice_mine=You're mine, %s!
|
||||||
actors.mobs.tengu.notice_face=Face me, %s!
|
actors.mobs.newtengu.notice_face=Face me, %s!
|
||||||
actors.mobs.tengu.interesting=Let's make this interesting...
|
actors.mobs.newtengu.interesting=Let's make this interesting...
|
||||||
actors.mobs.tengu.defeated=Free at last...
|
actors.mobs.newtengu.defeated=Free at last...
|
||||||
actors.mobs.tengu.rankings_desc=Assassinated by the Tengu
|
actors.mobs.newtengu.rankings_desc=Assassinated by the Tengu
|
||||||
actors.mobs.tengu.desc=A famous and enigmatic assassin, named for the mask grafted to his face.\n\nTengu is held down with large clasps on his wrists and knees, though he seems to have gotten rid of his chains long ago.\n\nHe will try to use traps, deceptive magic, and precise attacks to eliminate the only thing stopping his escape: you.
|
actors.mobs.newtengu.desc=A famous and enigmatic assassin, named for the mask grafted to his face.\n\nTengu is held down with large clasps on his wrists and knees, though he seems to have gotten rid of his chains long ago.\n\nHe will try to use traps, deceptive magic, and precise attacks to eliminate the only thing stopping his escape: you.
|
||||||
|
|
||||||
|
actors.mobs.oldtengu.name=Tengu
|
||||||
|
actors.mobs.oldtengu.notice_mine=You're mine, %s!
|
||||||
|
actors.mobs.oldtengu.notice_face=Face me, %s!
|
||||||
|
actors.mobs.oldtengu.interesting=Let's make this interesting...
|
||||||
|
actors.mobs.oldtengu.defeated=Free at last...
|
||||||
|
actors.mobs.oldtengu.rankings_desc=Assassinated by the Tengu
|
||||||
|
actors.mobs.oldtengu.desc=A famous and enigmatic assassin, named for the mask grafted to his face.\n\nTengu is held down with large clasps on his wrists and knees, though he seems to have gotten rid of his chains long ago.\n\nHe will try to use traps, deceptive magic, and precise attacks to eliminate the only thing stopping his escape: you.
|
||||||
|
|
||||||
actors.mobs.thief.name=crazy thief
|
actors.mobs.thief.name=crazy thief
|
||||||
actors.mobs.thief.stole=The thief stole %s from you!
|
actors.mobs.thief.stole=The thief stole %s from you!
|
||||||
|
|
|
@ -104,6 +104,8 @@ levels.traps.summoningtrap.desc=Triggering this trap will summon a number of thi
|
||||||
levels.traps.teleportationtrap.name=teleportation trap
|
levels.traps.teleportationtrap.name=teleportation trap
|
||||||
levels.traps.teleportationtrap.desc=Whatever triggers this trap will be teleported to some other location on this floor.
|
levels.traps.teleportationtrap.desc=Whatever triggers this trap will be teleported to some other location on this floor.
|
||||||
|
|
||||||
|
levels.traps.tengudarttrap.desc=Tengu has clearly been preparing for a fight. This trap will activate a hidden dart blower which will shoot a poison dart at the nearest thing that isn't Tengu.\n\nThe trap is so well made that the trigger mechanism is impossible to detect without magical aid. However the trap is visible for a moment when it is being set.
|
||||||
|
|
||||||
levels.traps.toxictrap.name=toxic gas trap
|
levels.traps.toxictrap.name=toxic gas trap
|
||||||
levels.traps.toxictrap.desc=Triggering this trap will set a cloud of toxic gas loose within the surrounding area.
|
levels.traps.toxictrap.desc=Triggering this trap will set a cloud of toxic gas loose within the surrounding area.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user