v2.3.0: added some very basic early gnoll sapper and guard interactions
This commit is contained in:
@@ -1208,8 +1208,15 @@ 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.gnollgeomancer.name=gnoll geomancer
|
||||
actors.mobs.gnollgeomancer.desc=TODO
|
||||
|
||||
actors.mobs.gnollguard.name=gnoll guard
|
||||
actors.mobs.gnollguard.desc=A large and tough looking gnoll wielding a spear and a shield. These guards are likely brutes in training, roped into helping protect the mine from encroaching wildlife.\n\nThe gnoll guard is strong enough to wield the spear in one hand, but can't use it very well. It will need fairly open space to attack at a distance, and will do notably less damage to you if you get up close.
|
||||
actors.mobs.gnollguard.desc=A large and tough looking gnoll wielding a spear and a shield, but no helmet. These guards are likely brutes in training, roped into helping protect the mine from encroaching wildlife.\n\nThe gnoll guard is strong enough to wield the spear in one hand, but can't use it very well. It will need fairly open space to attack at a distance, and will do notably less damage to you if you get up close.
|
||||
actors.mobs.gnollguard.desc_armor=A nearby sapper is holding a device that is granting this guard earthen armor, heavily reducing the damage it takes.
|
||||
|
||||
actors.mobs.gnollsapper.name=gnoll sapper
|
||||
actors.mobs.gnollsapper.desc=TODO
|
||||
|
||||
actors.mobs.gnolltrickster.name=gnoll trickster
|
||||
actors.mobs.gnolltrickster.desc=A strange looking creature, even by gnoll standards. It hunches forward with a wicked grin, almost cradling the satchel hanging over its shoulder. Its eyes are wide with a strange mix of fear and excitement.\n\nThere is a large collection of poorly made darts in its satchel, they all seem to be tipped with various harmful substances.
|
||||
|
||||
@@ -22,10 +22,13 @@
|
||||
package com.shatteredpixel.shatteredpixeldungeon.actors.mobs;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.items.weapon.melee.Spear;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.messages.Messages;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.GnollGuardSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
import com.watabou.utils.Random;
|
||||
|
||||
public class GnollGuard extends Mob {
|
||||
@@ -41,6 +44,38 @@ public class GnollGuard extends Mob {
|
||||
|
||||
loot = Spear.class;
|
||||
lootChance = 0.1f;
|
||||
|
||||
WANDERING = new Wandering();
|
||||
}
|
||||
|
||||
private int sapperID = -1;
|
||||
|
||||
public void linkSapper( GnollSapper sapper){
|
||||
this.sapperID = sapper.id();
|
||||
if (sprite instanceof GnollGuardSprite){
|
||||
((GnollGuardSprite) 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 GnollGuardSprite){
|
||||
((GnollGuardSprite) sprite).loseArmor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void damage(int dmg, Object src) {
|
||||
if (hasSapper()) dmg /= 4;
|
||||
super.damage(dmg, src);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,4 +105,38 @@ public class GnollGuard extends Mob {
|
||||
&& new Ballistica( enemy.pos, pos, Ballistica.PROJECTILE).collisionPos == pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() {
|
||||
if (hasSapper()){
|
||||
return super.description() + "\n\n" + Messages.get(this, "desc_armor");
|
||||
} else {
|
||||
return super.description();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String SAPPER_ID = "sapper_id";
|
||||
|
||||
@Override
|
||||
public void storeInBundle(Bundle bundle) {
|
||||
super.storeInBundle(bundle);
|
||||
bundle.put(SAPPER_ID, sapperID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
sapperID = bundle.getInt(SAPPER_ID);
|
||||
}
|
||||
|
||||
public class Wandering extends Mob.Wandering {
|
||||
@Override
|
||||
protected int randomDestination() {
|
||||
if (hasSapper()){
|
||||
return ((GnollSapper)Actor.findById(sapperID)).pos;
|
||||
} else {
|
||||
return super.randomDestination();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Pixel Dungeon
|
||||
* Copyright (C) 2012-2015 Oleg Dolya
|
||||
*
|
||||
* Shattered Pixel Dungeon
|
||||
* Copyright (C) 2014-2023 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.actors.Actor;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.sprites.GnollSapperSprite;
|
||||
import com.watabou.utils.Bundle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GnollSapper extends Mob {
|
||||
|
||||
{
|
||||
spriteClass = GnollSapperSprite.class;
|
||||
|
||||
HP = HT = 35;
|
||||
defenseSkill = 15;
|
||||
|
||||
EXP = 10;
|
||||
maxLvl = -2;
|
||||
|
||||
properties.add(Property.MINIBOSS);
|
||||
|
||||
SLEEPING = new Sleeping();
|
||||
state = SLEEPING;
|
||||
//TODO wandering and hunting too. Partly for abilities, but also for other logic
|
||||
}
|
||||
|
||||
private ArrayList<Integer> guardIDs = new ArrayList<>();
|
||||
|
||||
public void linkGuard(GnollGuard g){
|
||||
guardIDs.add(g.id());
|
||||
g.linkSapper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void die(Object cause) {
|
||||
super.die(cause);
|
||||
for (Integer g : guardIDs){
|
||||
if (Actor.findById(g) instanceof GnollGuard){
|
||||
((GnollGuard) Actor.findById(g)).loseSapper();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String GUARD_IDS = "guard_ids";
|
||||
|
||||
@Override
|
||||
public void storeInBundle(Bundle bundle) {
|
||||
super.storeInBundle(bundle);
|
||||
int[] toStore = new int[guardIDs.size()];
|
||||
for (int i = 0; i < toStore.length; i++){
|
||||
toStore[i] = guardIDs.get(i);
|
||||
}
|
||||
bundle.put(GUARD_IDS, toStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreFromBundle(Bundle bundle) {
|
||||
super.restoreFromBundle(bundle);
|
||||
guardIDs = new ArrayList<>();
|
||||
for (int g : bundle.getIntArray(GUARD_IDS)){
|
||||
guardIDs.add(g);
|
||||
}
|
||||
}
|
||||
|
||||
public class Sleeping extends Mob.Sleeping {
|
||||
|
||||
@Override
|
||||
public boolean act(boolean enemyInFOV, boolean justAlerted) {
|
||||
if (guardIDs.size() < 2){
|
||||
for (Char ch : Actor.chars()){
|
||||
if (fieldOfView[ch.pos] && ch instanceof GnollGuard && !guardIDs.contains(ch.id())){
|
||||
linkGuard((GnollGuard) ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.act(enemyInFOV, justAlerted);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,13 @@ public class EarthParticle extends PixelParticle {
|
||||
}
|
||||
};
|
||||
|
||||
public static final Emitter.Factory SMALL = new Factory() {
|
||||
@Override
|
||||
public void emit( Emitter emitter, int index, float x, float y ) {
|
||||
((EarthParticle)emitter.recycle( EarthParticle.class )).resetSmall( x, y );
|
||||
}
|
||||
};
|
||||
|
||||
public static final Emitter.Factory FALLING = new Factory() {
|
||||
@Override
|
||||
public void emit( Emitter emitter, int index, float x, float y ) {
|
||||
@@ -60,6 +67,13 @@ public class EarthParticle extends PixelParticle {
|
||||
size = 16;
|
||||
}
|
||||
|
||||
public void resetSmall( float x, float y ) {
|
||||
reset(x, y);
|
||||
|
||||
left = lifespan = 1f;
|
||||
size = 8;
|
||||
}
|
||||
|
||||
public void resetFalling( float x, float y ) {
|
||||
reset(x, y);
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.quest;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalGuardian;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGuard;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollSapper;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
|
||||
@@ -145,6 +147,21 @@ public class MineLargeRoom extends CaveRoom {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO refine this with barricades
|
||||
Point p = random(5);
|
||||
GnollSapper s = new GnollSapper();
|
||||
s.pos = level.pointToCell(p);
|
||||
level.mobs.add(s);
|
||||
Painter.set(level, p, Terrain.EMPTY);
|
||||
|
||||
p = random(4);
|
||||
GnollGuard g = new GnollGuard();
|
||||
g.pos = level.pointToCell(p);
|
||||
level.mobs.add(g);
|
||||
Painter.set(level, p, Terrain.EMPTY);
|
||||
|
||||
s.linkGuard(g);
|
||||
|
||||
} else {
|
||||
Painter.fillEllipse(level, this, 3, Terrain.EMPTY);
|
||||
}
|
||||
|
||||
@@ -22,10 +22,16 @@
|
||||
package com.shatteredpixel.shatteredpixeldungeon.sprites;
|
||||
|
||||
import com.shatteredpixel.shatteredpixeldungeon.Assets;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGuard;
|
||||
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.EarthParticle;
|
||||
import com.watabou.noosa.TextureFilm;
|
||||
import com.watabou.noosa.particles.Emitter;
|
||||
|
||||
public class GnollGuardSprite extends MobSprite {
|
||||
|
||||
private Emitter earthArmor;
|
||||
|
||||
public GnollGuardSprite() {
|
||||
super();
|
||||
|
||||
@@ -48,4 +54,58 @@ public class GnollGuardSprite extends MobSprite {
|
||||
play( idle );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void link( Char ch ) {
|
||||
super.link( ch );
|
||||
|
||||
if (ch instanceof GnollGuard && ((GnollGuard) ch).hasSapper()){
|
||||
setupArmor();
|
||||
}
|
||||
}
|
||||
|
||||
public void setupArmor(){
|
||||
if (earthArmor == null) {
|
||||
earthArmor = emitter();
|
||||
earthArmor.fillTarget = false;
|
||||
earthArmor.y = height()/2f;
|
||||
earthArmor.x = 2;
|
||||
earthArmor.width = width()-4;
|
||||
earthArmor.height = height() - 10f;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user