v2.3.0: lots more rough implementation work on gnoll geomancer

This commit is contained in:
Evan Debenham
2023-11-27 20:18:48 -05:00
parent 9fa8f123ee
commit 1a9bb22968
3 changed files with 145 additions and 11 deletions
@@ -49,6 +49,7 @@ import com.shatteredpixel.shatteredpixeldungeon.scenes.PixelScene;
import com.shatteredpixel.shatteredpixeldungeon.sprites.GnollGeomancerSprite;
import com.shatteredpixel.shatteredpixeldungeon.sprites.ItemSpriteSheet;
import com.shatteredpixel.shatteredpixeldungeon.sprites.MissileSprite;
import com.shatteredpixel.shatteredpixeldungeon.ui.BossHealthBar;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.noosa.audio.Sample;
import com.watabou.utils.Bundle;
@@ -88,8 +89,22 @@ public class GnollGeomancer extends Mob {
private int throwingRockFromPos = -1;
private int throwingRockToPos = -1;
int[] sapperSpawns = null;
@Override
protected boolean act() {
if (sapperSpawns == null){
sapperSpawns = new int[3];
int i = 0;
for (Mob m : Dungeon.level.mobs){
if (m instanceof GnollSapper){
sapperSpawns[i] = ((GnollSapper) m).spawnPos;
i++;
}
if (i == 3) break;
}
}
if (throwingRockFromPos != -1){
GnollGeomancer.doRockThrowAttack(this, throwingRockFromPos, throwingRockToPos);
@@ -170,10 +185,11 @@ public class GnollGeomancer extends Mob {
do {
target = Random.Int(Dungeon.level.length());
} while (!Dungeon.level.insideMap(target) || Dungeon.level.distance(pos, target) != 10);
carveRock(target);
carveRock(getDashPos());
state = HUNTING;
enemy = Dungeon.hero;
BossHealthBar.assignBoss(GnollGeomancer.this);
}
if (wasSleeping) {
@@ -199,26 +215,108 @@ public class GnollGeomancer extends Mob {
public void damage(int dmg, Object src) {
int hpBracket = HT / 3;
int beforeHitHP = HP;
int curbracket = HP / hpBracket;
if (curbracket == 3) curbracket--; //full HP isn't its own bracket
inFinalBracket = curbracket == 0;
super.damage(dmg, src);
//geomancer cannot be hit through multiple brackets at a time
if ((beforeHitHP/hpBracket - HP/hpBracket) >= 2){
HP = hpBracket * ((beforeHitHP/hpBracket)-1) + 1;
}
int newBracket = HP / hpBracket;
if (newBracket == 3) newBracket--; //full HP isn't its own bracket
if (newBracket != curbracket) {
//cannot be hit through multiple brackets at a time
if (HP <= (curbracket-1)*hpBracket){
HP = (curbracket-1)*hpBracket + 1;
}
BossHealthBar.bleed(newBracket <= 0);
//taking damage from full HP does not trigger a jump
if (beforeHitHP != HT && beforeHitHP / hpBracket != HP / hpBracket) {
//this is a start, but need a lot more fight logic
int target;
do {
target = Random.Int(Dungeon.level.length());
} while (!Dungeon.level.insideMap(target) || Dungeon.level.distance(pos, target) != 10);
carveRock(target);
carveRock(getDashPos());
Buff.affect(this, RockArmor.class).setShield(30);
}
}
private boolean inFinalBracket = false;
@Override
public boolean isAlive() {
//cannot die until final HP bracket, regardless of incoming dmg
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
//
private int getDashPos(){
int closestSapperPos = -1;
boolean closestisAlive = false;
for (int i = 0; i < sapperSpawns.length; i++){
if (sapperSpawns[i] == -1){
continue;
}
if (closestSapperPos == -1) {
closestSapperPos = sapperSpawns[i];
for (Mob m : Dungeon.level.mobs){
if (m instanceof GnollSapper && ((GnollSapper) m).spawnPos == closestSapperPos){
closestisAlive = true;
break;
}
}
continue;
}
boolean sapperAlive = false;
for (Mob m : Dungeon.level.mobs){
if (m instanceof GnollSapper && ((GnollSapper) m).spawnPos == sapperSpawns[i]){
sapperAlive = true;
break;
}
}
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;
}
}
}
//TODO get blink position
int dashPos = closestSapperPos;
//if spawn pos is more than 12 tiles away, get as close as possible
Ballistica path = new Ballistica(pos, dashPos, Ballistica.STOP_TARGET);
if (path.dist > 12){
dashPos = path.path.get(12);
}
//TODO move to adjacent cell if pos is occupied
for (int i = 0; i < sapperSpawns.length; i++){
if (sapperSpawns[i] == closestSapperPos){
sapperSpawns[i] = -1;
}
}
//TODO if geomancer alive, steal guard and set properties
return dashPos;
}
private void carveRock(int target){
Ballistica path = new Ballistica(pos, target, Ballistica.STOP_TARGET);
@@ -234,8 +332,13 @@ public class GnollGeomancer extends Mob {
Dungeon.level.drop(new DarkGold(), i).sprite.drop();
}
if (Dungeon.level.solid[i]){
//TODO boulders?
Dungeon.level.map[i] = Terrain.EMPTY_DECO;
if (Random.Int(3) == 0){
Dungeon.level.map[i] = Terrain.MINE_BOULDER;
} else {
Dungeon.level.map[i] = Terrain.EMPTY_DECO;
}
} else if (Dungeon.level.map[i] == Terrain.HIGH_GRASS || Dungeon.level.map[i] == Terrain.FURROWED_GRASS){
Dungeon.level.map[i] = Terrain.GRASS;
}
CellEmitter.get( i - Dungeon.level.width() ).start(Speck.factory(Speck.ROCK), 0.07f, 10);
}
@@ -392,6 +495,7 @@ public class GnollGeomancer extends Mob {
source.sprite.attack(from, new Callback() {
@Override
public void call() {
source.sprite.idle();
//do nothing
}
});
@@ -498,6 +602,7 @@ public class GnollGeomancer extends Mob {
@Override
public void call() {
//do nothing
source.sprite.idle();
}
});
@@ -529,6 +634,8 @@ 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_SPAWNS = "sapper_spawns";
@Override
public void storeInBundle(Bundle bundle) {
super.storeInBundle(bundle);
@@ -536,6 +643,10 @@ public class GnollGeomancer extends Mob {
bundle.put(ABILITY_COOLDOWN, abilityCooldown);
bundle.put(ROCK_FROM_POS, throwingRockFromPos);
bundle.put(ROCK_TO_POS, throwingRockToPos);
if (sapperSpawns != null){
bundle.put(SAPPER_SPAWNS, sapperSpawns);
}
}
@Override
@@ -545,5 +656,13 @@ public class GnollGeomancer extends Mob {
abilityCooldown = bundle.getInt(ABILITY_COOLDOWN);
throwingRockFromPos = bundle.getInt(ROCK_FROM_POS);
throwingRockToPos = bundle.getInt(ROCK_TO_POS);
if (bundle.contains(SAPPER_SPAWNS)) {
sapperSpawns = bundle.getIntArray(SAPPER_SPAWNS);
}
if (hits >= 3){
BossHealthBar.assignBoss(this);
}
}
}
@@ -59,6 +59,14 @@ public class GnollGeomancerSprite extends MobSprite {
scale.set(1.25f);
}
@Override
public void onComplete( Animation anim ) {
if (anim == zap) {
idle();
}
super.onComplete( anim );
}
@Override
public void idle() {
super.idle();
@@ -50,5 +50,12 @@ public class GnollSapperSprite extends MobSprite {
play( idle );
}
@Override
public void onComplete( Animation anim ) {
if (anim == zap) {
idle();
}
super.onComplete( anim );
}
}