v2.1.3: added basic mining and sub-floor functionality!

This commit is contained in:
Evan Debenham
2023-06-22 17:27:57 -04:00
parent 1e82b73c0c
commit 161a67b8e1
9 changed files with 209 additions and 4 deletions

Binary file not shown.

View File

@@ -206,6 +206,7 @@ public class Assets {
public static final String CHAINS = "sounds/chains.mp3";
public static final String SCAN = "sounds/scan.mp3";
public static final String SHEEP = "sounds/sheep.mp3";
public static final String MINE = "sounds/mine.mp3";
public static final String[] all = new String[]{
CLICK, BADGE, GOLD,
@@ -218,7 +219,7 @@ public class Assets {
DESCEND, EAT, READ, LULLABY, DRINK, SHATTER, ZAP, LIGHTNING, LEVELUP, DEATH,
CHALLENGE, CURSED, TRAP, EVOKE, TOMB, ALERT, MELD, BOSS, BLAST, PLANT, RAY, BEACON,
TELEPORT, CHARMS, MASTERY, PUFF, ROCKS, BURNING, FALLING, GHOST, SECRET, BONES,
BEE, DEGRADE, MIMIC, DEBUFF, CHARGEUP, GAS, CHAINS, SCAN, SHEEP
BEE, DEGRADE, MIMIC, DEBUFF, CHARGEUP, GAS, CHAINS, SCAN, SHEEP, MINE
};
}

View File

@@ -58,6 +58,7 @@ import com.shatteredpixel.shatteredpixeldungeon.levels.HallsBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.HallsLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.LastLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.MiningLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.PrisonLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel;
@@ -338,6 +339,17 @@ public class Dungeon {
default:
level = new DeadEndLevel();
}
} else if (branch == 1) {
switch (depth) {
case 11:
case 12:
case 13:
case 14:
level = new MiningLevel();
break;
default:
level = new DeadEndLevel();
}
} else {
level = new DeadEndLevel();
}

View File

@@ -108,6 +108,8 @@ import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfExperience
import com.shatteredpixel.shatteredpixeldungeon.items.potions.PotionOfHealing;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.elixirs.ElixirOfMight;
import com.shatteredpixel.shatteredpixeldungeon.items.potions.exotic.PotionOfDivineInspiration;
import com.shatteredpixel.shatteredpixeldungeon.items.quest.DarkGold;
import com.shatteredpixel.shatteredpixeldungeon.items.quest.Pickaxe;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfAccuracy;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfEvasion;
import com.shatteredpixel.shatteredpixeldungeon.items.rings.RingOfForce;
@@ -133,6 +135,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.weapon.missiles.MissileWea
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.journal.Notes;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.MiningLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.Chasm;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
@@ -804,7 +807,10 @@ public class Hero extends Char {
} else if (curAction instanceof HeroAction.Unlock) {
actResult = actUnlock((HeroAction.Unlock) curAction);
} else if (curAction instanceof HeroAction.LvlTransition) {
} else if (curAction instanceof HeroAction.Mine) {
actResult = actMine( (HeroAction.Mine)curAction );
}else if (curAction instanceof HeroAction.LvlTransition) {
actResult = actTransition( (HeroAction.LvlTransition)curAction );
} else if (curAction instanceof HeroAction.Attack) {
@@ -1132,6 +1138,50 @@ public class Hero extends Char {
return false;
}
}
public boolean actMine(HeroAction.Mine action){
if (Dungeon.level.adjacent(pos, action.dst)
&& (Dungeon.level.map[action.dst] == Terrain.WALL || Dungeon.level.map[action.dst] == Terrain.WALL_DECO)
&& Dungeon.level.insideMap(action.dst)){
sprite.attack(action.dst, new Callback() {
@Override
public void call() {
if (Dungeon.level.map[action.dst] == Terrain.WALL_DECO){
DarkGold gold = new DarkGold();
if (gold.doPickUp( Dungeon.hero )) {
GLog.i( Messages.capitalize(Messages.get(Dungeon.hero, "you_now_have", gold.name())) );
} else {
Dungeon.level.drop( gold, pos ).sprite.drop();
}
CellEmitter.center( action.dst ).burst( Speck.factory( Speck.STAR ), 7 );
Sample.INSTANCE.play( Assets.Sounds.EVOKE );
} else {
CellEmitter.get( action.dst ).burst( Speck.factory( Speck.ROCK ), 2 );
Sample.INSTANCE.play( Assets.Sounds.MINE );
}
PixelScene.shake(0.5f, 0.5f);
Level.set( action.dst, Terrain.EMPTY_DECO );
for (int i : PathFinder.NEIGHBOURS9) {
Dungeon.level.discoverable[action.dst + i] = true;
}
for (int i : PathFinder.NEIGHBOURS9) {
GameScene.updateMap( action.dst+i );
}
Dungeon.observe();
spendAndNext(TICK);
ready();
}
});
return false;
}
ready();
return false;
}
private boolean actTransition(HeroAction.LvlTransition action ) {
int stairs = action.dst;
@@ -1613,6 +1663,13 @@ public class Hero extends Char {
curAction = new HeroAction.Attack( ch );
}
//TODO perhaps only trigger this if hero is already adjacent? reducing mistaps
} else if (Dungeon.level instanceof MiningLevel &&
belongings.getItem(Pickaxe.class) != null &&
(Dungeon.level.map[cell] == Terrain.WALL || Dungeon.level.map[cell] == Terrain.WALL_DECO)){
curAction = new HeroAction.Mine( cell );
} else if (heap != null
//moving to an item doesn't auto-pickup when enemies are near...
&& (visibleEnemies.size() == 0 || cell == pos ||

View File

@@ -69,6 +69,12 @@ public class HeroAction {
this.dst = stairs;
}
}
public static class Mine extends HeroAction {
public Mine( int wall ) {
this.dst = wall;
}
}
public static class Alchemy extends HeroAction {
public Alchemy( int pot ) {

View File

@@ -0,0 +1,105 @@
/*
* 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.levels;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Bones;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.Actor;
import com.shatteredpixel.shatteredpixeldungeon.actors.Char;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.Mob;
import com.shatteredpixel.shatteredpixeldungeon.items.Heap;
import com.shatteredpixel.shatteredpixeldungeon.items.Item;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard.CaveRoom;
public class MiningLevel extends Level {
{
color1 = 0x534f3e;
color2 = 0xb9d661;
}
@Override
public String tilesTex() {
return Assets.Environment.TILES_CAVES;
}
@Override
public String waterTex() {
return Assets.Environment.WATER_CAVES;
}
@Override
protected boolean build() {
//a few niceties are needed here before putting this out, things like water, short grass
// tile deco, and a pause to hunger/regen
setSize(32, 32);
CaveRoom c = new CaveRoom();
c.set(1, 1, 31, 31);
c.paint(this);
Painter.fill(this, 15, 15, 3, 3, Terrain.EMPTY);
int entrance = 16 * width() + 16;
transitions.add(new LevelTransition(this,
entrance,
LevelTransition.Type.BRANCH_ENTRANCE,
Dungeon.depth,
0,
LevelTransition.Type.BRANCH_EXIT));
map[entrance] = Terrain.ENTRANCE;
return true;
}
@Override
public Mob createMob() {
return null;
}
@Override
protected void createMobs() {
}
public Actor addRespawner() {
return null;
}
@Override
protected void createItems() {
Item item = Bones.get();
if (item != null) {
drop( item, entrance()-width() ).setHauntedIfCursed().type = Heap.Type.REMAINS;
}
}
@Override
public int randomRespawnCell( Char ch ) {
return entrance()-width();
}
}

View File

@@ -21,10 +21,12 @@
package com.shatteredpixel.shatteredpixeldungeon.levels.rooms.standard;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.actors.mobs.npcs.Blacksmith;
import com.shatteredpixel.shatteredpixeldungeon.items.Generator;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.features.LevelTransition;
import com.shatteredpixel.shatteredpixeldungeon.levels.painters.Painter;
import com.shatteredpixel.shatteredpixeldungeon.levels.traps.BurningTrap;
import com.watabou.utils.Point;
@@ -72,6 +74,22 @@ public class BlacksmithRoom extends StandardRoom {
} while (level.heaps.get( npc.pos ) != null);
level.mobs.add( npc );
// TODO need to add some better visuals here (even just a simple custom asset)
Random.pushGenerator(Dungeon.seedCurDepth()+1);
int entrancePos;
do {
entrancePos = level.pointToCell(random( 2 ));
} while (level.heaps.get( npc.pos ) != null || entrancePos == npc.pos);
Random.popGenerator();
level.transitions.add(new LevelTransition(level,
entrancePos,
LevelTransition.Type.BRANCH_EXIT,
Dungeon.depth,
Dungeon.branch+1,
LevelTransition.Type.BRANCH_ENTRANCE));
Painter.set(level, entrancePos, Terrain.EXIT);
for(Point p : getPoints()) {
int cell = level.pointToCell(p);
if (level.map[cell] == Terrain.TRAP){

View File

@@ -60,6 +60,7 @@ import com.shatteredpixel.shatteredpixeldungeon.items.scrolls.ScrollOfTeleportat
import com.shatteredpixel.shatteredpixeldungeon.journal.Document;
import com.shatteredpixel.shatteredpixeldungeon.journal.Journal;
import com.shatteredpixel.shatteredpixeldungeon.levels.Level;
import com.shatteredpixel.shatteredpixeldungeon.levels.MiningLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.RegularLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.shatteredpixel.shatteredpixeldungeon.levels.rooms.Room;
@@ -428,6 +429,9 @@ public class GameScene extends PixelScene {
break;
}
}
if (Dungeon.level instanceof MiningLevel){
add(new WndStory(Messages.get(this, "blacksmith_quest_window_title") + ":\n\n" + Messages.get(this, "blacksmith_quest_window")).setDelays(0.6f, 1.4f));
}
if (Dungeon.hero.isAlive()) {
Badges.validateNoKilling();
}

View File

@@ -24,6 +24,7 @@ package com.shatteredpixel.shatteredpixeldungeon.tiles;
import com.shatteredpixel.shatteredpixeldungeon.Assets;
import com.shatteredpixel.shatteredpixeldungeon.Dungeon;
import com.shatteredpixel.shatteredpixeldungeon.levels.HallsBossLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.MiningLevel;
import com.shatteredpixel.shatteredpixeldungeon.levels.Terrain;
import com.watabou.noosa.TextureFilm;
import com.watabou.noosa.Tilemap;
@@ -107,9 +108,10 @@ public class WallBlockingTilemap extends Tilemap {
//- none of the remaining 5 neighbour cells are both not a wall and visible
//if all 3 above are wall we can shortcut and just clear the cell
//unless one or more is a shelf, then we have to just block none
//unless one or more is a shelf, or we can mine, then we have to just block none
if (wall(cell - 1 - mapWidth) && wall(cell - mapWidth) && wall(cell + 1 - mapWidth)){
if (shelf(cell - 1 - mapWidth) || shelf(cell - mapWidth) || shelf(cell + 1 - mapWidth)){
if (shelf(cell - 1 - mapWidth) || shelf(cell - mapWidth)
|| shelf(cell + 1 - mapWidth) || Dungeon.level instanceof MiningLevel){
curr = BLOCK_NONE;
} else {
curr = CLEARED;