v3.1.0: finished impl on gnoll exiles

This commit is contained in:
Evan Debenham
2025-05-05 16:24:21 -04:00
parent d880102af4
commit 1303e90765
5 changed files with 104 additions and 16 deletions

View File

@@ -1595,9 +1595,11 @@ actors.mobs.gnoll.name=gnoll scout
actors.mobs.gnoll.desc=Gnolls are hyena-like humanoids. They dwell in sewers and dungeons, venturing up to raid the surface from time to time. Gnoll scouts are regular members of their pack, they are not as strong as brutes and not as intelligent as shamans.
actors.mobs.gnollexile.name=gnoll exile
actors.mobs.gnollexile.desc=Gnolls are sometimes exiled from their society for a variety of reasons. The unusual grey fur on this gnoll indicates it was probably kicked out for just not fitting in. Exiles have to be strong and smart to survive, this one looks like it knows how to use the spear its holding.
actors.mobs.gnollexile.desc_passive=_The gnoll exile isn't moving to attack._ It doesn't seem as aggressive as the other gnolls here, it probably doesn't want a fight. You could just let it pass, although it has a backpack that might be full of useful items...
actors.mobs.gnollexile.desc=This grey-furred gnoll has a large mark on its shoulder, denoting it as an exile. Gnolls are usually exiled from their society for ignoring orders or breaking laws. Exiles have to be strong and shrewd to survive, this one looks like it knows how to use the spear its holding.
actors.mobs.gnollexile.desc_passive=_The gnoll exile isn't moving to attack._ It doesn't seem as aggressive as the other gnolls here, and probably doesn't think that fighting you is worth it. You could just let it pass, but it has a backpack that might be full of useful items...
actors.mobs.gnollexile.desc_aggro=_The gnoll exile looks around angrily._ It seems something has made it decide to fight after all. Watch out for that spear!
actors.mobs.gnollexile.seen_passive=The spear-wielding gnoll looks at you warily, but doesn't move to attack.
actors.mobs.gnollexile.seen_aggro=The spear-wielding gnoll moves to attack!
actors.mobs.gnollgeomancer.name=gnoll geomancer
actors.mobs.gnollgeomancer.warning=The geomancer begins to stir. Make sure you're ready before you continue!

View File

@@ -24,32 +24,52 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.GnollExileSprite;
import com.shatteredpixel.shatteredpixeldungeon.utils.GLog;
import com.watabou.utils.BArray;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
import java.util.ArrayList;
public class GnollExile extends Gnoll {
//has 2x HP, +50% other stats, and +1 reach vs. a regular gnoll scout
//in exchange, they do not aggro automatically, and drop extra loot
{
spriteClass = GnollExileSprite.class;
PASSIVE = new Passive();
WANDERING = new Wandering();
state = PASSIVE;
loot = Gold.class;
defenseSkill = 6;
HP = HT = 24;
loot = Generator.randomUsingDefaults();
lootChance = 1f;
}
//TODO higher stats, more detailed behaviour, better loot
@Override
public int damageRoll() {
return Random.NormalIntRange( 1, 10 );
}
//"the spear-wielding gnoll pauses and eyes you suspiciously, but doesn't move to attack"
//"After a moment the gnoll nods its head toward you and begins to move on"
@Override
public int attackSkill( Char target ) {
return 15;
}
// offer 1 ration to get all of its drops
@Override
public int drRoll() {
return super.drRoll() + Random.NormalIntRange(0, 3);
}
//has 1 extra reach from their spear
@Override
protected boolean canAttack( Char enemy ) {
if (Dungeon.level.adjacent( pos, enemy.pos )){
@@ -72,6 +92,37 @@ public class GnollExile extends Gnoll {
return super.canAttack(enemy);
}
@Override
public void rollToDropLoot() {
super.rollToDropLoot();
if (Dungeon.hero.lvl > maxLvl + 2) return;
//in addition to normal drop drop, also drops 1 or 2 random extras
ArrayList<Item> items = new ArrayList<>();
items.add(Generator.randomUsingDefaults());
if (Random.Int(2) == 0) items.add(Generator.randomUsingDefaults());
for (Item item : items){
int ofs;
do {
ofs = PathFinder.NEIGHBOURS8[Random.Int(8)];
} while (Dungeon.level.solid[pos + ofs] && !Dungeon.level.passable[pos + ofs]);
Dungeon.level.drop( item, pos + ofs ).sprite.drop( pos );
}
}
@Override
public void beckon(int cell) {
if (state != PASSIVE) {
super.beckon(cell);
} else {
//still attracts if passive, but doesn't remove passive state
target = cell;
}
}
@Override
public String description() {
String desc = super.description();
@@ -83,14 +134,36 @@ public class GnollExile extends Gnoll {
return desc;
}
//while passive gnoll exiles wander around
//gnoll exiles wander around while passive
private class Passive extends Mob.Wandering {
private int seenNotifyCooldown = 0;
@Override
public boolean act( boolean enemyInFOV, boolean justAlerted ) {
for (Buff b : buffs()){
if (b.type == Buff.buffType.NEGATIVE){
//swap to aggro if we've been debuffed
state = WANDERING;
return true;
}
}
if (fieldOfView[Dungeon.hero.pos] && Dungeon.level.heroFOV[pos]){
if (seenNotifyCooldown <= 0){
GLog.p(Messages.get(GnollExile.class, "seen_passive"));
}
seenNotifyCooldown = 10;
} else {
seenNotifyCooldown--;
}
if (enemyInFOV && justAlerted) {
//TODO pause if hero first enters fov?
if (Dungeon.level.heroFOV[pos]) {
GLog.w(Messages.get(GnollExile.class, "seen_aggro"));
}
return noticeEnemy();
} else {
@@ -100,4 +173,14 @@ public class GnollExile extends Gnoll {
}
}
}
//standard wandering but with a warning that the exile is aggroed
private class Wandering extends Mob.Wandering {
@Override
protected boolean noticeEnemy() {
GLog.w(Messages.get(GnollExile.class, "seen_aggro"));
return super.noticeEnemy();
}
}
}

View File

@@ -241,7 +241,9 @@ public class Mimic extends Mob {
@Override
public void beckon( int cell ) {
// Do nothing
if (alignment != Alignment.NEUTRAL) {
super.beckon(cell);
}
}
@Override

View File

@@ -24,7 +24,6 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.items.trinkets.RatSkull;
import com.watabou.utils.DeviceCompat;
import com.watabou.utils.Random;
import java.util.ArrayList;
@@ -248,7 +247,7 @@ public class MobSpawner extends Actor {
Class<? extends Mob> cl = rotation.get(i);
if (cl == Rat.class) {
cl = Albino.class;
} else if (cl == Gnoll.class && DeviceCompat.isDebug()) {
} else if (cl == Gnoll.class) {
cl = GnollExile.class;
} else if (cl == Slime.class) {
cl = CausticSlime.class;

View File

@@ -143,7 +143,9 @@ public class Statue extends Mob {
@Override
public void beckon( int cell ) {
// Do nothing
if (state != PASSIVE){
super.beckon(cell);
}
}
@Override