v3.1.0: rough initial impl for gnoll exiles

This commit is contained in:
Evan Debenham
2025-04-14 15:11:23 -04:00
parent c55ccb26d7
commit c7a7cf8955
7 changed files with 178 additions and 15 deletions

View File

@@ -1594,6 +1594,11 @@ actors.mobs.ghoul.desc=As dwarven society slowly began to collapse, and the curr
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_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.gnollgeomancer.name=gnoll geomancer
actors.mobs.gnollgeomancer.warning=The geomancer begins to stir. Make sure you're ready before you continue!
actors.mobs.gnollgeomancer.alert=The geomancer awakens! The entire cave seems to shift as it leaps away while laughing madly!

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1004 B

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -23,7 +23,6 @@ package com.shatteredpixel.shatteredpixeldungeon.actors.buffs;
import com.shatteredpixel.shatteredpixeldungeon.Challenges;
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.blobs.Fire;
@@ -31,8 +30,8 @@ import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene;
import com.shatteredpixel.shatteredpixeldungeon.ui.BuffIndicator;
import com.watabou.utils.BArray;
import com.watabou.noosa.Image;
import com.watabou.utils.BArray;
import com.watabou.utils.Bundle;
import com.watabou.utils.PathFinder;
import com.watabou.utils.Random;
@@ -162,10 +161,9 @@ public abstract class ChampionEnemy extends Buff {
return false;
} else {
boolean[] passable = BArray.not(Dungeon.level.solid, null);
for (Char ch : Actor.chars()) {
//our own tile is always passable
passable[ch.pos] = ch == target;
}
//our own tile is always passable
passable[target.pos] = true;
PathFinder.buildDistanceMap(enemy.pos, passable, 4);
@@ -209,10 +207,9 @@ public abstract class ChampionEnemy extends Buff {
return false;
} else {
boolean[] passable = BArray.not(Dungeon.level.solid, null);
for (Char ch : Actor.chars()) {
//our own tile is always passable
passable[ch.pos] = ch == target;
}
//our own tile is always passable
passable[target.pos] = true;
PathFinder.buildDistanceMap(enemy.pos, passable, 2);

View File

@@ -0,0 +1,103 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2025 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.Char;
import com.shatteredpixel.shatteredpixeldungeon.items.Gold;
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
import com.shatteredpixel.shatteredpixeldungeon.sprites.GnollExileSprite;
import com.watabou.utils.BArray;
import com.watabou.utils.PathFinder;
public class GnollExile extends Gnoll {
{
spriteClass = GnollExileSprite.class;
PASSIVE = new Passive();
state = PASSIVE;
loot = Gold.class;
lootChance = 1f;
}
//TODO higher stats, more detailed behaviour, better loot
//"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"
// offer 1 ration to get all of its drops
//has 1 extra reach from their spear
@Override
protected boolean canAttack( Char enemy ) {
if (Dungeon.level.adjacent( pos, enemy.pos )){
return true;
}
if (Dungeon.level.distance( pos, enemy.pos ) <= 2){
boolean[] passable = BArray.not(Dungeon.level.solid, null);
//our own tile is always passable
passable[pos] = true;
PathFinder.buildDistanceMap(enemy.pos, passable, 2);
if (PathFinder.distance[pos] <= 2){
return true;
}
}
return super.canAttack(enemy);
}
@Override
public String description() {
String desc = super.description();
if (state == PASSIVE){
desc += "\n\n" + Messages.get(this, "desc_passive");
} else {
desc += "\n\n" + Messages.get(this, "desc_aggro");
}
return desc;
}
//while passive gnoll exiles wander around
private class Passive extends Mob.Wandering {
@Override
public boolean act( boolean enemyInFOV, boolean justAlerted ) {
if (enemyInFOV && justAlerted) {
//TODO pause if hero first enters fov?
return noticeEnemy();
} else {
return continueWandering();
}
}
}
}

View File

@@ -24,6 +24,7 @@ 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;
@@ -247,6 +248,8 @@ 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()) {
cl = GnollExile.class;
} else if (cl == Slime.class) {
cl = CausticSlime.class;
} else if (cl == Thief.class) {

View File

@@ -0,0 +1,53 @@
/*
* Pixel Dungeon
* Copyright (C) 2012-2015 Oleg Dolya
*
* Shattered Pixel Dungeon
* Copyright (C) 2014-2025 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.watabou.noosa.TextureFilm;
public class GnollExileSprite extends MobSprite {
public GnollExileSprite() {
super();
texture( Assets.Sprites.GNOLL );
TextureFilm frames = new TextureFilm( texture, 12, 15 );
int c = 21;
idle = new Animation( 2, true );
idle.frames( frames, 0+c, 0+c, 0+c, 1+c, 0+c, 0+c, 1+c, 1+c );
run = new Animation( 12, true );
run.frames( frames, 4+c, 5+c, 6+c, 7+c );
attack = new Animation( 12, false );
attack.frames( frames, 2+c, 3+c, 0+c );
die = new Animation( 12, false );
die.frames( frames, 8+c, 9+c, 10+c );
play( idle );
}
}

View File

@@ -39,19 +39,21 @@ public class GnollTricksterSprite extends MobSprite {
TextureFilm frames = new TextureFilm( texture, 12, 15 );
int c = 42;
idle = new MovieClip.Animation( 2, true );
idle.frames( frames, 21, 21, 21, 22, 21, 21, 22, 22 );
idle.frames( frames, 0+c, 0+c, 0+c, 1+c, 0+c, 0+c, 1+c, 1+c );
run = new MovieClip.Animation( 12, true );
run.frames( frames, 25, 26, 27, 28 );
run.frames( frames, 4+c, 5+c, 6+c, 7+c );
attack = new MovieClip.Animation( 12, false );
attack.frames( frames, 23, 24, 21 );
attack.frames( frames, 2+c, 3+c, 0+c );
cast = attack.clone();
die = new MovieClip.Animation( 12, false );
die.frames( frames, 29, 30, 31 );
die = new Animation( 12, false );
die.frames( frames, 8+c, 9+c, 10+c );
play( idle );
}