v2.3.0: implemented gnoll geomancer's interaction with living sappers
This commit is contained in:
@@ -39,6 +39,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.TargetedCell;
|
||||
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.ScrollOfTeleportation;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.wands.WandOfBlastWave;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
@@ -89,7 +90,8 @@ public class GnollGeomancer extends Mob {
|
||||
private int throwingRockFromPos = -1;
|
||||
private int throwingRockToPos = -1;
|
||||
|
||||
int[] sapperSpawns = null;
|
||||
private int sapperID = -1;
|
||||
private int[] sapperSpawns = null;
|
||||
|
||||
@Override
|
||||
protected boolean act() {
|
||||
@@ -121,7 +123,9 @@ public class GnollGeomancer extends Mob {
|
||||
|
||||
@Override
|
||||
public boolean isInvulnerable(Class effect) {
|
||||
return super.isInvulnerable(effect) || (buff(RockArmor.class) != null && effect != Pickaxe.class);
|
||||
return super.isInvulnerable(effect)
|
||||
|| (buff(RockArmor.class) != null && effect != Pickaxe.class)
|
||||
|| hasSapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -251,11 +255,7 @@ public class GnollGeomancer extends Mob {
|
||||
return super.isAlive() || !inFinalBracket;
|
||||
}
|
||||
|
||||
//we pick location to jump to based on sapper positions:
|
||||
//first aim for closest living sapper, moving 8-12 tiles, preferring to go 10
|
||||
//otherwise aim to closest dead sapper pos
|
||||
//if we arrive at (or are near enough to) a sapper pos, we claim that sapper
|
||||
//
|
||||
//aim for closest sapper, preferring living ones within 16 tiles
|
||||
private int getDashPos(){
|
||||
|
||||
int closestSapperPos = -1;
|
||||
@@ -284,16 +284,13 @@ public class GnollGeomancer extends Mob {
|
||||
}
|
||||
}
|
||||
|
||||
if (Dungeon.level.distance(pos, sapperSpawns[i]) <= 16) {
|
||||
if (sapperAlive && !closestisAlive
|
||||
|| Dungeon.level.distance(pos, sapperSpawns[i]) < Dungeon.level.distance(pos, closestSapperPos)) {
|
||||
closestSapperPos = sapperSpawns[i];
|
||||
closestisAlive = sapperAlive;
|
||||
}
|
||||
if ((sapperAlive && !closestisAlive && Dungeon.level.distance(pos, sapperSpawns[i]) <= 16)
|
||||
|| Dungeon.level.distance(pos, sapperSpawns[i]) < Dungeon.level.distance(pos, closestSapperPos)) {
|
||||
closestSapperPos = sapperSpawns[i];
|
||||
closestisAlive = sapperAlive;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO get blink position
|
||||
int dashPos = closestSapperPos;
|
||||
|
||||
//if spawn pos is more than 12 tiles away, get as close as possible
|
||||
@@ -303,7 +300,17 @@ public class GnollGeomancer extends Mob {
|
||||
dashPos = path.path.get(12);
|
||||
}
|
||||
|
||||
//TODO move to adjacent cell if pos is occupied
|
||||
if (Actor.findChar(dashPos) != null){
|
||||
ArrayList<Integer> candidates = new ArrayList<>();
|
||||
for (int i : PathFinder.NEIGHBOURS8){
|
||||
if (Actor.findChar(dashPos+i) == null && Dungeon.level.traps.get(dashPos+i) == null){
|
||||
candidates.add(dashPos+i);
|
||||
}
|
||||
}
|
||||
if (!candidates.isEmpty()) {
|
||||
dashPos = Random.element(candidates);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < sapperSpawns.length; i++){
|
||||
if (sapperSpawns[i] == closestSapperPos){
|
||||
@@ -311,12 +318,51 @@ public class GnollGeomancer extends Mob {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO if geomancer alive, steal guard and set properties
|
||||
if (closestisAlive){
|
||||
GnollSapper closest = null;
|
||||
for (Mob m : Dungeon.level.mobs){
|
||||
if (m instanceof GnollSapper && ((GnollSapper) m).spawnPos == closestSapperPos){
|
||||
closest = (GnollSapper) m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (closest != null){
|
||||
closest.linkPartner(this);
|
||||
//moves sapper toward geomancer if it is too far away
|
||||
if (Dungeon.level.distance(closest.pos, dashPos) > 3){
|
||||
int newSapperPos = new Ballistica(dashPos, closest.pos, Ballistica.STOP_TARGET).path.get(1);
|
||||
ScrollOfTeleportation.appear(closest, newSapperPos);
|
||||
closest.spawnPos = newSapperPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dashPos;
|
||||
|
||||
}
|
||||
|
||||
public void linkSapper( GnollSapper sapper ){
|
||||
this.sapperID = sapper.id();
|
||||
if (sprite instanceof GnollGeomancerSprite){
|
||||
((GnollGeomancerSprite) sprite).setupArmor();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSapper(){
|
||||
return sapperID != -1
|
||||
&& Actor.findById(sapperID) instanceof GnollSapper
|
||||
&& ((GnollSapper)Actor.findById(sapperID)).isAlive();
|
||||
}
|
||||
|
||||
public void loseSapper(){
|
||||
if (sapperID != -1){
|
||||
sapperID = -1;
|
||||
if (sprite instanceof GnollGeomancerSprite){
|
||||
((GnollGeomancerSprite) sprite).loseArmor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void carveRock(int target){
|
||||
Ballistica path = new Ballistica(pos, target, Ballistica.STOP_TARGET);
|
||||
|
||||
@@ -410,9 +456,7 @@ public class GnollGeomancer extends Mob {
|
||||
return true;
|
||||
} else {
|
||||
enemySeen = true;
|
||||
//sprite.showStatus(CharSprite.DEFAULT, "seen");
|
||||
|
||||
//TODO cooldown
|
||||
if (abilityCooldown-- <= 0){
|
||||
//do we care?
|
||||
boolean targetNextToBarricade = false;
|
||||
@@ -634,6 +678,7 @@ public class GnollGeomancer extends Mob {
|
||||
private static final String ROCK_FROM_POS = "rock_from_pos";
|
||||
private static final String ROCK_TO_POS = "rock_to_pos";
|
||||
|
||||
private static final String SAPPER_ID = "sapper_id";
|
||||
private static final String SAPPER_SPAWNS = "sapper_spawns";
|
||||
|
||||
@Override
|
||||
@@ -644,6 +689,7 @@ public class GnollGeomancer extends Mob {
|
||||
bundle.put(ROCK_FROM_POS, throwingRockFromPos);
|
||||
bundle.put(ROCK_TO_POS, throwingRockToPos);
|
||||
|
||||
bundle.put(SAPPER_ID, sapperID);
|
||||
if (sapperSpawns != null){
|
||||
bundle.put(SAPPER_SPAWNS, sapperSpawns);
|
||||
}
|
||||
@@ -657,6 +703,7 @@ public class GnollGeomancer extends Mob {
|
||||
throwingRockFromPos = bundle.getInt(ROCK_FROM_POS);
|
||||
throwingRockToPos = bundle.getInt(ROCK_TO_POS);
|
||||
|
||||
sapperID = bundle.getInt(SAPPER_ID);
|
||||
if (bundle.contains(SAPPER_SPAWNS)) {
|
||||
sapperSpawns = bundle.getIntArray(SAPPER_SPAWNS);
|
||||
}
|
||||
|
||||
@@ -55,24 +55,38 @@ public class GnollSapper extends Mob {
|
||||
}
|
||||
|
||||
public int spawnPos;
|
||||
private int guardID = -1;
|
||||
private int partnerID = -1;
|
||||
|
||||
private int abilityCooldown = Random.NormalIntRange(4, 6);
|
||||
|
||||
private int throwingRockFromPos = -1;
|
||||
private int throwingRockToPos = -1;
|
||||
|
||||
public void linkGuard(GnollGuard g){
|
||||
guardID = g.id();
|
||||
g.linkSapper(this);
|
||||
public void linkPartner(Char c){
|
||||
losePartner();
|
||||
partnerID = c.id();
|
||||
if (c instanceof GnollGuard) {
|
||||
((GnollGuard) c).linkSapper(this);
|
||||
} else if (c instanceof GnollGeomancer){
|
||||
((GnollGeomancer) c).linkSapper(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void losePartner(){
|
||||
if (partnerID != -1){
|
||||
if (Actor.findById(partnerID) instanceof GnollGuard) {
|
||||
((GnollGuard) Actor.findById(partnerID)).loseSapper();
|
||||
} else if (Actor.findById(partnerID) instanceof GnollGeomancer) {
|
||||
((GnollGeomancer) Actor.findById(partnerID)).loseSapper();
|
||||
}
|
||||
partnerID = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die(Object cause) {
|
||||
super.die(cause);
|
||||
if (guardID != -1 && Actor.findById(guardID) instanceof GnollGuard){
|
||||
((GnollGuard) Actor.findById(guardID)).loseSapper();
|
||||
}
|
||||
losePartner();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,10 +138,10 @@ public class GnollSapper extends Mob {
|
||||
} else {
|
||||
enemySeen = true;
|
||||
|
||||
if (Actor.findById(guardID) instanceof GnollGuard
|
||||
if (Actor.findById(partnerID) != null
|
||||
&& Dungeon.level.distance(pos, enemy.pos) <= 3){
|
||||
((GnollGuard) Actor.findById(guardID)).target = enemy.pos;
|
||||
((GnollGuard) Actor.findById(guardID)).aggro(enemy);
|
||||
((Mob) Actor.findById(partnerID)).target = enemy.pos;
|
||||
((Mob) Actor.findById(partnerID)).aggro(enemy);
|
||||
}
|
||||
|
||||
if (abilityCooldown-- <= 0){
|
||||
@@ -185,7 +199,7 @@ public class GnollSapper extends Mob {
|
||||
}
|
||||
|
||||
private static final String SPAWN_POS = "spawn_pos";
|
||||
private static final String GUARD_ID = "guard_id";
|
||||
private static final String PARTNER_ID = "partner_id";
|
||||
|
||||
private static final String ABILITY_COOLDOWN = "ability_cooldown";
|
||||
private static final String ROCK_FROM_POS = "rock_from_pos";
|
||||
@@ -194,7 +208,7 @@ public class GnollSapper extends Mob {
|
||||
@Override
|
||||
public void storeInBundle(Bundle bundle) {
|
||||
super.storeInBundle(bundle);
|
||||
bundle.put(GUARD_ID, guardID);
|
||||
bundle.put(PARTNER_ID, partnerID);
|
||||
bundle.put(SPAWN_POS, spawnPos);
|
||||
bundle.put(ABILITY_COOLDOWN, abilityCooldown);
|
||||
bundle.put(ROCK_FROM_POS, throwingRockFromPos);
|
||||
@@ -204,7 +218,7 @@ public class GnollSapper extends Mob {
|
||||
@Override
|
||||
public void restoreFromBundle(Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
guardID = bundle.getInt( GUARD_ID );
|
||||
partnerID = bundle.getInt(PARTNER_ID);
|
||||
spawnPos = bundle.getInt(SPAWN_POS);
|
||||
abilityCooldown = bundle.getInt(ABILITY_COOLDOWN);
|
||||
throwingRockFromPos = bundle.getInt(ROCK_FROM_POS);
|
||||
|
||||
@@ -65,6 +65,10 @@ public class EarthParticle extends PixelParticle {
|
||||
|
||||
left = lifespan = 0.5f;
|
||||
size = 16;
|
||||
|
||||
acc.y = 0;
|
||||
speed.y = 0;
|
||||
angularSpeed = 0;
|
||||
}
|
||||
|
||||
public void resetSmall( float x, float y ) {
|
||||
|
||||
@@ -137,7 +137,7 @@ public class MineLargeRoom extends CaveRoom {
|
||||
GnollGuard g = new GnollGuard();
|
||||
g.pos = guardPos;
|
||||
level.mobs.add(g);
|
||||
s.linkGuard(g);
|
||||
s.linkPartner(g);
|
||||
|
||||
int barricades = Random.Int(2) == 0 ? 2 : 1;
|
||||
for (int i = 0; i < barricades; i ++){
|
||||
|
||||
@@ -27,6 +27,7 @@ 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.Paralysis;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGeomancer;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGuard;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.CellEmitter;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.Speck;
|
||||
@@ -78,7 +79,7 @@ public class GnollRockfallTrap extends RockfallTrap {
|
||||
|
||||
Char ch = Actor.findChar( cell );
|
||||
|
||||
if (ch != null && ch.isAlive()){
|
||||
if (ch != null && ch.isAlive() && !(ch instanceof GnollGeomancer)){
|
||||
//5-10 less damage than normal rockfall traps
|
||||
int damage = Random.NormalIntRange(scalingDepth(), scalingDepth()*2);
|
||||
damage -= ch.drRoll();
|
||||
@@ -91,7 +92,8 @@ public class GnollRockfallTrap extends RockfallTrap {
|
||||
Dungeon.fail( this );
|
||||
GLog.n( Messages.get(this, "ondeath") );
|
||||
}
|
||||
} else if (Dungeon.level instanceof MiningLevel
|
||||
} else if (ch == null
|
||||
&& Dungeon.level instanceof MiningLevel
|
||||
&& Dungeon.level.traps.get(cell) == null
|
||||
&& Dungeon.level.plants.get(cell) == null
|
||||
&& Random.Int(2) == 0){
|
||||
|
||||
@@ -22,14 +22,19 @@
|
||||
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGeomancer;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.EarthParticle;
|
||||
import com.watabou.noosa.TextureFilm;
|
||||
import com.watabou.noosa.particles.Emitter;
|
||||
import com.watabou.utils.ColorMath;
|
||||
|
||||
public class GnollGeomancerSprite extends MobSprite {
|
||||
|
||||
private Animation statue;
|
||||
|
||||
private Emitter earthArmor;
|
||||
|
||||
public GnollGeomancerSprite() {
|
||||
super();
|
||||
|
||||
@@ -59,6 +64,62 @@ public class GnollGeomancerSprite extends MobSprite {
|
||||
scale.set(1.25f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link( Char ch ) {
|
||||
super.link( ch );
|
||||
|
||||
if (ch instanceof GnollGeomancer && ((GnollGeomancer) ch).hasSapper()){
|
||||
setupArmor();
|
||||
}
|
||||
if (ch != null && ch.buff(GnollGeomancer.RockArmor.class) != null){
|
||||
play( statue );
|
||||
}
|
||||
}
|
||||
|
||||
public void setupArmor(){
|
||||
if (earthArmor == null) {
|
||||
earthArmor = emitter();
|
||||
earthArmor.fillTarget = false;
|
||||
earthArmor.y = height()/2f;
|
||||
earthArmor.x = (2*scale.x);
|
||||
earthArmor.width = width()-(4*scale.x);
|
||||
earthArmor.height = height() - (10*scale.y);
|
||||
earthArmor.pour(EarthParticle.SMALL, 0.15f);
|
||||
}
|
||||
}
|
||||
|
||||
public void loseArmor(){
|
||||
if (earthArmor != null){
|
||||
earthArmor.on = false;
|
||||
earthArmor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
super.update();
|
||||
|
||||
if (earthArmor != null){
|
||||
earthArmor.visible = visible;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die() {
|
||||
super.die();
|
||||
if (earthArmor != null){
|
||||
earthArmor.on = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void kill() {
|
||||
super.kill();
|
||||
if (earthArmor != null){
|
||||
earthArmor.killAndErase();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete( Animation anim ) {
|
||||
if (anim == zap) {
|
||||
|
||||
@@ -68,9 +68,9 @@ public class GnollGuardSprite extends MobSprite {
|
||||
earthArmor = emitter();
|
||||
earthArmor.fillTarget = false;
|
||||
earthArmor.y = height()/2f;
|
||||
earthArmor.x = 2;
|
||||
earthArmor.width = width()-4;
|
||||
earthArmor.height = height() - 10f;
|
||||
earthArmor.x = (2*scale.x);
|
||||
earthArmor.width = width()-(4*scale.x);
|
||||
earthArmor.height = height() - (10*scale.y);
|
||||
earthArmor.pour(EarthParticle.SMALL, 0.15f);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user