v2.3.0: added fungal sentries, with WIP visuals and bare mechanics

This commit is contained in:
Evan Debenham
2023-12-18 15:07:34 -05:00
parent bc4663e81d
commit be29c81ef3
7 changed files with 241 additions and 14 deletions

View File

@@ -1202,6 +1202,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.fungalsentry.name=fungal sentry
actors.mobs.fungalsentry.desc=This especially tall mushroom acts as a point of defense for the larger fungal network living in this cave.\n\nIt is immobile, but will shoot precise blasts of poison at anything that gets within its line of sight. While the impact of these blasts is fairly weak, _they can stack up deadly amounts of poison very quickly._ While it can be killed, it's probably best to avoid it.
actors.mobs.fungalspinner.name=fungal spinner
actors.mobs.fungalspinner.desc=This cave spinner appears to be being controlled by a parasitic fungus. The fungus has also changed its abilities, replacing its web and venom sacks with fungal growth.\n\nThe fungal spinner will spit plant life at you instead of webs, spreading fungal vegetation and potentially rooting you. While it can't poison, the fungal spinner will gain substantial damage resistance if it is adjacent to any mushrooms.

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

View File

@@ -312,15 +312,16 @@ public class Assets {
public static final String PYLON = "sprites/pylon.png";
public static final String DM200 = "sprites/dm200.png";
public static final String LOTUS = "sprites/lotus.png";
public static final String NINJA_LOG= "sprites/ninja_log.png";
public static final String SPIRIT_HAWK= "sprites/spirit_hawk.png";
public static final String RED_SENTRY= "sprites/red_sentry.png";
public static final String CRYSTAL_WISP= "sprites/crystal_wisp.png";
public static final String CRYSTAL_GUARDIAN= "sprites/crystal_guardian.png";
public static final String CRYSTAL_SPIRE= "sprites/crystal_spire.png";
public static final String GNOLL_GUARD= "sprites/gnoll_guard.png";
public static final String GNOLL_SAPPER= "sprites/gnoll_sapper.png";
public static final String GNOLL_GEOMANCER = "sprites/gnoll_geomancer.png";
public static final String FUNGAL_SPINNER = "sprites/fungal_spinner.png";
public static final String NINJA_LOG = "sprites/ninja_log.png";
public static final String SPIRIT_HAWK = "sprites/spirit_hawk.png";
public static final String RED_SENTRY = "sprites/red_sentry.png";
public static final String CRYSTAL_WISP = "sprites/crystal_wisp.png";
public static final String CRYSTAL_GUARDIAN = "sprites/crystal_guardian.png";
public static final String CRYSTAL_SPIRE = "sprites/crystal_spire.png";
public static final String GNOLL_GUARD = "sprites/gnoll_guard.png";
public static final String GNOLL_SAPPER = "sprites/gnoll_sapper.png";
public static final String GNOLL_GEOMANCER = "sprites/gnoll_geomancer.png";
public static final String FUNGAL_SPINNER = "sprites/fungal_spinner.png";
public static final String FUNGAL_SENTRY = "sprites/fungal_sentry.png";
}
}

View File

@@ -0,0 +1,117 @@
/*
* 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.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.blobs.ToxicGas;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Buff;
import com.shatteredpixel.shatteredpixeldungeon.actors.buffs.Poison;
import com.shatteredpixel.shatteredpixeldungeon.mechanics.Ballistica;
import com.shatteredpixel.shatteredpixeldungeon.sprites.FungalSentrySprite;
import com.watabou.utils.Random;
public class FungalSentry extends Mob {
{
spriteClass = FungalSentrySprite.class;
HP = HT = 200;
defenseSkill = 12;
EXP = 10;
maxLvl = -2;
state = WANDERING = new Waiting();
properties.add(Property.IMMOVABLE);
properties.add(Property.MINIBOSS);
}
@Override
public boolean reset() {
return true;
}
@Override
protected boolean getCloser(int target) {
return false;
}
@Override
protected boolean getFurther(int target) {
return false;
}
@Override
public int damageRoll() {
return Random.NormalIntRange(5, 10);
}
@Override
//TODO attack is a little permissive atm?
protected boolean canAttack( Char enemy ) {
return super.canAttack(enemy)
|| new Ballistica( pos, enemy.pos, Ballistica.MAGIC_BOLT).collisionPos == enemy.pos;
}
//TODO if we want to allow them to be literally killed, probably should give them a heal if hero is out of FOV, or similar
@Override
public int attackProc(Char enemy, int damage) {
Buff.affect(enemy, Poison.class).extend(6);
return super.attackProc(enemy, damage);
}
@Override
public int attackSkill( Char target ) {
return 50;
}
{
immunities.add( ToxicGas.class );
immunities.add( Poison.class );
}
private class Waiting extends Mob.Wandering{
@Override
public boolean act( boolean enemyInFOV, boolean justAlerted ) {
//always notices the hero
if (enemyInFOV) {
return noticeEnemy();
} else {
return continueWandering();
}
}
@Override
protected boolean noticeEnemy() {
spend(TICK);
return super.noticeEnemy();
}
}
}

View File

@@ -27,6 +27,7 @@ import com.shatteredpixel.shatteredpixeldungeon.effects.particles.CorrosionParti
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ElmoParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.FlameParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.LeafParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PoisonParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.PurpleParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.RainbowParticle;
import com.shatteredpixel.shatteredpixeldungeon.effects.particles.ShadowParticle;
@@ -66,12 +67,12 @@ public class MagicMissile extends Emitter {
public static final int RAINBOW = 8;
public static final int EARTH = 9;
public static final int WARD = 10;
public static final int SHAMAN_RED = 11;
public static final int SHAMAN_BLUE = 12;
public static final int SHAMAN_PURPLE = 13;
public static final int TOXIC_VENT = 14;
public static final int ELMO = 15;
public static final int POISON = 16;
public static final int MAGIC_MISS_CONE = 100;
public static final int FROST_CONE = 101;
@@ -166,7 +167,6 @@ public class MagicMissile extends Emitter {
size( 4 );
pour( WardParticle.FACTORY, 0.01f );
break;
case SHAMAN_RED:
size( 2 );
pour( ShamanParticle.RED, 0.01f );
@@ -187,6 +187,10 @@ public class MagicMissile extends Emitter {
size( 5 );
pour( ElmoParticle.FACTORY, 0.01f );
break;
case POISON:
size( 3 );
pour( PoisonParticle.MISSILE, 0.01f );
break;
case MAGIC_MISS_CONE:
size( 10 );

View File

@@ -22,9 +22,9 @@
package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.quest;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.CrystalGuardian;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.FungalSentry;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollGuard;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.GnollSapper;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.RotLasher;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
@@ -199,11 +199,15 @@ public class MineLargeRoom extends CaveRoom {
}
Point p = center();
RotLasher m = new RotLasher(); //placeholder enemy
FungalSentry m = new FungalSentry();
m.pos = level.pointToCell(p);
level.mobs.add(m);
Painter.set(level, p, Terrain.GRASS);
//no high grass directly above the sentry
p.y--;
Painter.set(level, p, Terrain.GRASS);
} else {
Painter.fillEllipse(level, this, 3, Terrain.EMPTY);
}

View File

@@ -0,0 +1,98 @@
/*
* 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.sprites;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.effects.MagicMissile;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.watabou.noosa.TextureFilm;
import com.watabou.utils.Callback;
public class FungalSentrySprite extends CharSprite {
private int cellToAttack;
public FungalSentrySprite(){
super();
texture(Assets.Sprites.FUNGAL_SENTRY );
TextureFilm frames = new TextureFilm( texture, 18, 18 );
idle = new Animation( 0, true );
idle.frames( frames, 0);
run = new Animation( 0, true );
run.frames( frames, 0);
attack = new Animation( 24, false );
attack.frames( frames, 0 );
zap = attack.clone();
die = new Animation( 12, false );
die.frames( frames, 0 );
play( idle );
}
//TODO blood
@Override
public void attack( int cell ) {
if (!Dungeon.level.adjacent( cell, ch.pos )) {
cellToAttack = cell;
zap(cell);
} else {
super.attack( cell );
}
}
@Override
public void onComplete( Animation anim ) {
if (anim == zap) {
idle();
MagicMissile.boltFromChar(parent, MagicMissile.POISON, this, cellToAttack, new Callback() {
@Override
public void call() {
ch.onAttackComplete();
}
} );
} else {
super.onComplete( anim );
}
}
public class ScorpioShot extends Item {
{
image = ItemSpriteSheet.FISHING_SPEAR;
}
}
}