From b26919e38195b0a98bcc8d4644e1ee1de279e569 Mon Sep 17 00:00:00 2001 From: Evan Debenham Date: Sat, 16 Nov 2019 14:44:43 -0500 Subject: [PATCH] v0.8.0: roughly implemented new dwarven ghouls --- core/src/main/assets/ghoul.png | Bin 0 -> 5089 bytes .../shatteredpixeldungeon/Assets.java | 1 + .../actors/mobs/Ghoul.java | 140 ++++++++++++++++++ .../actors/mobs/Mob.java | 60 +++++--- .../sprites/GhoulSprite.java | 52 +++++++ .../messages/actors/actors.properties | 3 + 6 files changed, 232 insertions(+), 24 deletions(-) create mode 100644 core/src/main/assets/ghoul.png create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java create mode 100644 core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java diff --git a/core/src/main/assets/ghoul.png b/core/src/main/assets/ghoul.png new file mode 100644 index 0000000000000000000000000000000000000000..ac64eef5c904a1fff5c811384abe8fb30c3247b5 GIT binary patch literal 5089 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 Dd9j$e literal 0 HcmV?d00001 diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java index 0cd629b61..f9aa1373d 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/Assets.java @@ -102,6 +102,7 @@ public class Assets { public static final String SLIME = "slime.png"; public static final String SNAKE = "snake.png"; public static final String NECRO = "necromancer.png"; + public static final String GHOUL = "ghoul.png"; public static final String ITEMS = "items.png"; public static final String TERRAIN_FEATURES = "terrain_features.png"; diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java new file mode 100644 index 000000000..a5226d287 --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Ghoul.java @@ -0,0 +1,140 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 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 + */ + +package com.shatteredpixel.shatteredpixeldungeon.actors.mobs; + +import com.shatteredpixel.shatteredpixeldungeon.Dungeon; +import com.shatteredpixel.shatteredpixeldungeon.actors.Actor; +import com.shatteredpixel.shatteredpixeldungeon.effects.Pushing; +import com.shatteredpixel.shatteredpixeldungeon.scenes.GameScene; +import com.shatteredpixel.shatteredpixeldungeon.sprites.GhoulSprite; +import com.watabou.utils.Bundle; +import com.watabou.utils.Random; + +import java.util.ArrayList; + +//TODO some aspects of existing enemy AI make these really wonky. Need to address that. +public class Ghoul extends Mob { + + { + spriteClass = GhoulSprite.class; + + HP = HT = 50; + defenseSkill = 18; + + EXP = 5; + maxLvl = 20; + + SLEEPING = new Sleeping(); + WANDERING = new Wandering(); + state = SLEEPING; + + properties.add(Property.UNDEAD); + } + + private int partnerID = -1; + private static final String PARTNER_ID = "partner_id"; + + @Override + public void storeInBundle( Bundle bundle ) { + super.storeInBundle( bundle ); + bundle.put( PARTNER_ID, partnerID ); + } + + @Override + public void restoreFromBundle( Bundle bundle ) { + super.restoreFromBundle( bundle ); + partnerID = bundle.getInt( PARTNER_ID ); + } + + @Override + protected boolean act() { + //create a child + if (partnerID == -1){ + + ArrayList candidates = new ArrayList<>(); + + int[] neighbours = {pos + 1, pos - 1, pos + Dungeon.level.width(), pos - Dungeon.level.width()}; + for (int n : neighbours) { + if (Dungeon.level.passable[n] && Actor.findChar( n ) == null) { + candidates.add( n ); + } + } + + if (!candidates.isEmpty()){ + Ghoul child = new Ghoul(); + child.partnerID = this.id(); + this.partnerID = child.id(); + if (state != SLEEPING) { + child.state = child.WANDERING; + } + + child.pos = Random.element( candidates ); + + Dungeon.level.occupyCell(child); + + GameScene.add( child ); + if (sprite.visible) { + Actor.addDelayed( new Pushing( child, pos, child.pos ), -1 ); + } + } + + } + return super.act(); + } + + private class Sleeping extends Mob.Sleeping { + @Override + public boolean act( boolean enemyInFOV, boolean justAlerted ) { + Ghoul partner = (Ghoul) Actor.findById( partnerID ); + if (partner != null && partner.state != partner.SLEEPING){ + state = WANDERING; + target = partner.pos; + return true; + } else { + return super.act( enemyInFOV, justAlerted ); + } + } + } + + private class Wandering extends Mob.Wandering { + + @Override + protected boolean continueWandering() { + enemySeen = false; + + Ghoul partner = (Ghoul) Actor.findById( partnerID ); + if (partner != null && (partner.state != partner.WANDERING || Dungeon.level.distance( pos, partner.target) > 1)){ + target = partner.pos; + int oldPos = pos; + if (getCloser( target )){ + spend( 1 / speed() ); + return moveSprite( oldPos, pos ); + } else { + spend( TICK ); + return true; + } + } else { + return super.continueWandering(); + } + } + } +} diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java index 6e78a0e3a..63285a740 100644 --- a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/actors/mobs/Mob.java @@ -750,37 +750,49 @@ public abstract class Mob extends Char { public boolean act( boolean enemyInFOV, boolean justAlerted ) { if (enemyInFOV && (justAlerted || Random.Float( distance( enemy ) / 2f + enemy.stealth() ) < 1)) { - enemySeen = true; - - notice(); - alerted = true; - state = HUNTING; - target = enemy.pos; - - if (Dungeon.isChallenged( Challenges.SWARM_INTELLIGENCE )) { - for (Mob mob : Dungeon.level.mobs) { - if (Dungeon.level.distance(pos, mob.pos) <= 8 && mob.state != mob.HUNTING) { - mob.beckon( target ); - } - } - } + return noticeEnemy(); } else { - enemySeen = false; - - int oldPos = pos; - if (target != -1 && getCloser( target )) { - spend( 1 / speed() ); - return moveSprite( oldPos, pos ); - } else { - target = Dungeon.level.randomDestination(); - spend( TICK ); - } + return continueWandering(); } + } + + protected boolean noticeEnemy(){ + enemySeen = true; + + notice(); + alerted = true; + state = HUNTING; + target = enemy.pos; + + if (Dungeon.isChallenged( Challenges.SWARM_INTELLIGENCE )) { + for (Mob mob : Dungeon.level.mobs) { + if (Dungeon.level.distance(pos, mob.pos) <= 8 && mob.state != mob.HUNTING) { + mob.beckon( target ); + } + } + } + return true; } + + protected boolean continueWandering(){ + enemySeen = false; + + int oldPos = pos; + if (target != -1 && getCloser( target )) { + spend( 1 / speed() ); + return moveSprite( oldPos, pos ); + } else { + target = Dungeon.level.randomDestination(); + spend( TICK ); + } + + return true; + } + } protected class Hunting implements AiState { diff --git a/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java new file mode 100644 index 000000000..794443e5d --- /dev/null +++ b/core/src/main/java/com/shatteredpixel/shatteredpixeldungeon/sprites/GhoulSprite.java @@ -0,0 +1,52 @@ +/* + * Pixel Dungeon + * Copyright (C) 2012-2015 Oleg Dolya + * + * Shattered Pixel Dungeon + * Copyright (C) 2014-2019 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 + */ + +package com.shatteredpixel.shatteredpixeldungeon.sprites; + +import com.shatteredpixel.shatteredpixeldungeon.Assets; +import com.watabou.noosa.TextureFilm; + +//TODO currently just a recolored monk sprite +public class GhoulSprite extends MobSprite { + + public GhoulSprite() { + super(); + + texture( Assets.GHOUL ); + + TextureFilm frames = new TextureFilm( texture, 15, 14 ); + + idle = new Animation( 6, true ); + idle.frames( frames, 1, 0, 1, 2 ); + + run = new Animation( 15, true ); + run.frames( frames, 11, 12, 13, 14, 15, 16 ); + + attack = new Animation( 12, false ); + attack.frames( frames, 3, 4, 3, 4 ); + + die = new Animation( 15, false ); + die.frames( frames, 1, 7, 8, 8, 9, 10 ); + + play( idle ); + } + +} diff --git a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties index c814a1980..7e03a1b6e 100644 --- a/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties +++ b/core/src/main/resources/com/shatteredpixel/shatteredpixeldungeon/messages/actors/actors.properties @@ -494,6 +494,9 @@ actors.mobs.eye.desc=Evil Eyes are floating balls of pent up demonic energy. Whi actors.mobs.fetidrat.name=fetid rat actors.mobs.fetidrat.desc=Something is clearly wrong with this rat. Its greasy black fur and rotting skin are very different from the healthy rats you've seen previously. Its pale green eyes make it seem especially menacing.\n\nThe rat carries a cloud of horrible stench with it, it's overpoweringly strong up close.\n\nDark ooze dribbles from the rat's mouth, it eats through the floor but seems to dissolve in water. +actors.mobs.ghoul.name=dwarven ghoul +actors.mobs.ghoul.desc=TODO + 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.