World gen rewrite, big cleanup, new items & Chest tile.

v5stable
Ondřej Hruška 11 years ago
parent f71fa66c1e
commit 1ca0b9e0e9
  1. BIN
      res/img/items.png
  2. BIN
      res/img/items.xcf
  3. BIN
      res/img/tiles.png
  4. BIN
      res/img/tiles.xcf
  5. 4
      src/mightypork/gamecore/app/BaseApp.java
  6. 13
      src/mightypork/gamecore/eventbus/EventBus.java
  7. 31
      src/mightypork/gamecore/util/Utils.java
  8. 37
      src/mightypork/gamecore/util/error/CorruptDataException.java
  9. 37
      src/mightypork/gamecore/util/error/CorruptedDataException.java
  10. 12
      src/mightypork/gamecore/util/error/IllegalValueException.java
  11. 5
      src/mightypork/gamecore/util/error/KeyAlreadyExistsException.java
  12. 10
      src/mightypork/gamecore/util/ion/IonInput.java
  13. 23
      src/mightypork/gamecore/util/math/Calc.java
  14. 31
      src/mightypork/gamecore/util/math/Range.java
  15. 2
      src/mightypork/gamecore/util/math/algo/Coord.java
  16. 20
      src/mightypork/gamecore/util/math/algo/Move.java
  17. 95
      src/mightypork/gamecore/util/math/algo/Moves.java
  18. 79
      src/mightypork/gamecore/util/math/algo/Sides.java
  19. 8
      src/mightypork/gamecore/util/math/algo/floodfill/FloodFill.java
  20. 16
      src/mightypork/gamecore/util/math/algo/pathfinding/PathFinder.java
  21. 6
      src/mightypork/gamecore/util/math/algo/pathfinding/PathFinderProxy.java
  22. 2
      src/mightypork/gamecore/util/math/color/pal/CMDR.java
  23. 1
      src/mightypork/gamecore/util/math/color/pal/RGB.java
  24. 50
      src/mightypork/gamecore/util/objects/ObjectUtils.java
  25. 119
      src/mightypork/gamecore/util/strings/AlphanumComparator.java
  26. 2
      src/mightypork/rogue/GameLoop.java
  27. 17
      src/mightypork/rogue/Res.java
  28. 22
      src/mightypork/rogue/screens/game/HudLayer.java
  29. 2
      src/mightypork/rogue/screens/game/IngameNav.java
  30. 4
      src/mightypork/rogue/screens/game/InvSlot.java
  31. 16
      src/mightypork/rogue/screens/game/InventoryLayer.java
  32. 6
      src/mightypork/rogue/screens/game/NavButton.java
  33. 34
      src/mightypork/rogue/screens/game/ScreenGame.java
  34. 2
      src/mightypork/rogue/screens/game/WorldConsoleRenderer.java
  35. 2
      src/mightypork/rogue/screens/menu/ScreenMainMenu.java
  36. 4
      src/mightypork/rogue/screens/select_world/WorldSlot.java
  37. 16
      src/mightypork/rogue/world/Inventory.java
  38. 18
      src/mightypork/rogue/world/PlayerControl.java
  39. 30
      src/mightypork/rogue/world/PlayerFacade.java
  40. 39
      src/mightypork/rogue/world/WorldConsole.java
  41. 10
      src/mightypork/rogue/world/entity/EntityPathFinder.java
  42. 6
      src/mightypork/rogue/world/entity/impl/BossRatAi.java
  43. 10
      src/mightypork/rogue/world/entity/impl/MonsterAi.java
  44. 20
      src/mightypork/rogue/world/entity/modules/EntityModulePosition.java
  45. 4
      src/mightypork/rogue/world/entity/modules/EntityPos.java
  46. 2
      src/mightypork/rogue/world/entity/render/EntityRendererMobLR.java
  47. 253
      src/mightypork/rogue/world/gen/LevelBuilder.java
  48. 124
      src/mightypork/rogue/world/gen/LevelGenerator.java
  49. 3
      src/mightypork/rogue/world/gen/MapTheme.java
  50. 2
      src/mightypork/rogue/world/gen/RoomBuilder.java
  51. 6
      src/mightypork/rogue/world/gen/RoomEntry.java
  52. 28
      src/mightypork/rogue/world/gen/Rooms.java
  53. 414
      src/mightypork/rogue/world/gen/ScratchMap.java
  54. 125
      src/mightypork/rogue/world/gen/WorldCreator.java
  55. 10
      src/mightypork/rogue/world/gen/rooms/AbstractRectRoom.java
  56. 38
      src/mightypork/rogue/world/gen/rooms/BossRoom.java
  57. 6
      src/mightypork/rogue/world/gen/rooms/DeadEndRoom.java
  58. 25
      src/mightypork/rogue/world/gen/rooms/ItemShrineRoom.java
  59. 16
      src/mightypork/rogue/world/gen/rooms/Rooms.java
  60. 50
      src/mightypork/rogue/world/gen/rooms/StorageRoom.java
  61. 33
      src/mightypork/rogue/world/gen/rooms/TreasureChestRoom.java
  62. 38
      src/mightypork/rogue/world/gen/rooms/TreasureRoom.java
  63. 7
      src/mightypork/rogue/world/gen/themes/ThemeBrick.java
  64. 8
      src/mightypork/rogue/world/gui/interaction/MIPKeyboard.java
  65. 10
      src/mightypork/rogue/world/gui/interaction/MIPMouse.java
  66. 12
      src/mightypork/rogue/world/item/Items.java
  67. 2
      src/mightypork/rogue/world/item/impl/active/ItemHeartPiece.java
  68. 2
      src/mightypork/rogue/world/item/impl/food/ItemCheese.java
  69. 2
      src/mightypork/rogue/world/item/impl/food/ItemMeat.java
  70. 2
      src/mightypork/rogue/world/item/impl/food/ItemSandwich.java
  71. 10
      src/mightypork/rogue/world/item/impl/weapons/ItemAxe.java
  72. 2
      src/mightypork/rogue/world/item/impl/weapons/ItemBone.java
  73. 2
      src/mightypork/rogue/world/item/impl/weapons/ItemClub.java
  74. 45
      src/mightypork/rogue/world/item/impl/weapons/ItemKnife.java
  75. 6
      src/mightypork/rogue/world/item/impl/weapons/ItemRock.java
  76. 4
      src/mightypork/rogue/world/item/impl/weapons/ItemSword.java
  77. 45
      src/mightypork/rogue/world/item/impl/weapons/ItemTwig.java
  78. 8
      src/mightypork/rogue/world/level/Level.java
  79. 4
      src/mightypork/rogue/world/level/render/TileRenderContext.java
  80. 2
      src/mightypork/rogue/world/tile/Tile.java
  81. 22
      src/mightypork/rogue/world/tile/TileColors.java
  82. 83
      src/mightypork/rogue/world/tile/TileRenderer.java
  83. 18
      src/mightypork/rogue/world/tile/TileType.java
  84. 1
      src/mightypork/rogue/world/tile/Tiles.java
  85. 101
      src/mightypork/rogue/world/tile/impl/TileBaseChest.java
  86. 9
      src/mightypork/rogue/world/tile/impl/TileBaseEntrance.java
  87. 9
      src/mightypork/rogue/world/tile/impl/TileBaseExit.java
  88. 10
      src/mightypork/rogue/world/tile/impl/TileBaseSecretDoor.java
  89. 10
      src/mightypork/rogue/world/tile/impl/TileWithItems.java
  90. 25
      src/mightypork/rogue/world/tile/impl/brick/TileBrickChest.java
  91. 6
      src/mightypork/rogue/world/tile/impl/brick/TileBrickDoor.java
  92. 2
      src/mightypork/rogue/world/tile/impl/brick/TileBrickEntrance.java
  93. 2
      src/mightypork/rogue/world/tile/impl/brick/TileBrickExit.java
  94. 2
      src/mightypork/rogue/world/tile/impl/brick/TileBrickFloor.java
  95. 2
      src/mightypork/rogue/world/tile/impl/brick/TileBrickPassage.java
  96. 6
      src/mightypork/rogue/world/tile/impl/brick/TileBrickSecretDoor.java
  97. 2
      src/mightypork/rogue/world/tile/impl/brick/TileBrickWall.java
  98. 50
      src/mightypork/rogue/world/tile/render/ChestRenderer.java

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

@ -21,7 +21,7 @@ import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.files.InstanceLock; import mightypork.gamecore.util.files.InstanceLock;
import mightypork.gamecore.util.ion.Ion; import mightypork.gamecore.util.ion.Ion;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
/** /**
@ -153,7 +153,7 @@ public abstract class BaseApp implements AppAccess, UncaughtExceptionHandler {
protected void registerIonizables() protected void registerIonizables()
{ {
Ion.registerType(Coord.ION_MARK, Coord.class); Ion.registerType(Coord.ION_MARK, Coord.class);
Ion.registerType(Step.ION_MARK, Step.class); Ion.registerType(Move.ION_MARK, Move.class);
} }

@ -15,6 +15,7 @@ import mightypork.gamecore.eventbus.event_flags.ImmediateEvent;
import mightypork.gamecore.eventbus.event_flags.NotLoggedEvent; import mightypork.gamecore.eventbus.event_flags.NotLoggedEvent;
import mightypork.gamecore.eventbus.events.Destroyable; import mightypork.gamecore.eventbus.events.Destroyable;
import mightypork.gamecore.logging.Log; import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.Utils;
/** /**
@ -142,10 +143,6 @@ final public class EventBus implements Destroyable, BusAccess {
/** Messages queued for delivery */ /** Messages queued for delivery */
private final DelayQueue<DelayQueueEntry> sendQueue = new DelayQueue<>(); private final DelayQueue<DelayQueueEntry> sendQueue = new DelayQueue<>();
private volatile boolean sendingDirect = false;
private BusEvent<?> lastEvt;
/** /**
* Make a new bus and start it's queue thread. * Make a new bus and start it's queue thread.
@ -180,13 +177,13 @@ final public class EventBus implements Destroyable, BusAccess {
{ {
assertLive(); assertLive();
final DelayedEvent adelay = event.getClass().getAnnotation(DelayedEvent.class); final DelayedEvent adelay = Utils.getAnnotation(event, DelayedEvent.class);
if (adelay != null) { if (adelay != null) {
sendDelayed(event, adelay.delay()); sendDelayed(event, adelay.delay());
return; return;
} }
if (event.getClass().isAnnotationPresent(ImmediateEvent.class)) { if (Utils.hasAnnotation(event, ImmediateEvent.class)) {
sendDirect(event); sendDirect(event);
return; return;
} }
@ -364,7 +361,6 @@ final public class EventBus implements Destroyable, BusAccess {
for (int i = 0; i < 2; i++) { // two tries. for (int i = 0; i < 2; i++) { // two tries.
// channels.setBuffering(true);
for (final EventChannel<?, ?> b : channels) { for (final EventChannel<?, ?> b : channels) {
if (b.canBroadcast(event)) { if (b.canBroadcast(event)) {
accepted = true; accepted = true;
@ -373,7 +369,6 @@ final public class EventBus implements Destroyable, BusAccess {
if (event.isConsumed()) break; if (event.isConsumed()) break;
} }
// channels.setBuffering(false);
if (!accepted) if (addChannelForEvent(event)) continue; if (!accepted) if (addChannelForEvent(event)) continue;
@ -388,7 +383,7 @@ final public class EventBus implements Destroyable, BusAccess {
private boolean shallLog(BusEvent<?> event) private boolean shallLog(BusEvent<?> event)
{ {
if (!detailedLogging) return false; if (!detailedLogging) return false;
if (event.getClass().isAnnotationPresent(NotLoggedEvent.class)) return false; if (Utils.hasAnnotation(event, NotLoggedEvent.class)) return false;
return true; return true;
} }

@ -1,6 +1,9 @@
package mightypork.gamecore.util; package mightypork.gamecore.util;
import java.lang.annotation.Annotation;
/** /**
* Assorted utils * Assorted utils
* *
@ -14,4 +17,32 @@ public final class Utils {
t.start(); t.start();
return t; return t;
} }
public static boolean hasAnnotation(Object tested, Class<? extends Annotation> annotation)
{
return tested.getClass().isAnnotationPresent(annotation);
}
public static <T extends Annotation> T getAnnotation(Object tested, Class<T> annotation)
{
return tested.getClass().getAnnotation(annotation);
}
/**
* Pick first non-null option
*
* @param options options
* @return the selected option
*/
public static Object fallback(Object... options)
{
for (final Object o : options) {
if (o != null) return o;
}
return null; // all null
}
} }

@ -0,0 +1,37 @@
package mightypork.gamecore.util.error;
import java.io.IOException;
/**
* Thrown when data could not be read successfully.
*
* @author MightyPork
*/
public class CorruptDataException extends IOException {
public CorruptDataException()
{
super();
}
public CorruptDataException(String message, Throwable cause)
{
super(message, cause);
}
public CorruptDataException(String message)
{
super(message);
}
public CorruptDataException(Throwable cause)
{
super(cause);
}
}

@ -1,37 +0,0 @@
package mightypork.gamecore.util.error;
import java.io.IOException;
/**
* To be used when a data could not be read successfully.
*
* @author MightyPork
*/
public class CorruptedDataException extends IOException {
public CorruptedDataException()
{
super();
}
public CorruptedDataException(String message, Throwable cause)
{
super(message, cause);
}
public CorruptedDataException(String message)
{
super(message);
}
public CorruptedDataException(Throwable cause)
{
super(cause);
}
}

@ -1,6 +1,12 @@
package mightypork.gamecore.util.error; package mightypork.gamecore.util.error;
/**
* Thrown when a invalid value is given to a method, or found in a data object /
* file etc
*
* @author MightyPork
*/
public class IllegalValueException extends RuntimeException { public class IllegalValueException extends RuntimeException {
public IllegalValueException() public IllegalValueException()
@ -25,10 +31,4 @@ public class IllegalValueException extends RuntimeException {
super(message, cause); super(message, cause);
} }
public IllegalValueException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace)
{
super(message, cause, enableSuppression, writableStackTrace);
}
} }

@ -1,6 +1,11 @@
package mightypork.gamecore.util.error; package mightypork.gamecore.util.error;
/**
* Thrown by a map-like class when the key specified is already taken.
*
* @author MightyPork
*/
public class KeyAlreadyExistsException extends RuntimeException { public class KeyAlreadyExistsException extends RuntimeException {
public KeyAlreadyExistsException() public KeyAlreadyExistsException()

@ -10,7 +10,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import mightypork.gamecore.util.error.CorruptedDataException; import mightypork.gamecore.util.error.CorruptDataException;
/** /**
@ -360,7 +360,7 @@ public class IonInput {
return readStrings(); return readStrings();
default: default:
throw new CorruptedDataException("Invalid mark: " + mark); throw new CorruptDataException("Invalid mark: " + mark);
} }
} }
@ -378,7 +378,7 @@ public class IonInput {
if (mark == Ion.ENTRY) return true; if (mark == Ion.ENTRY) return true;
if (mark == Ion.END) return false; if (mark == Ion.END) return false;
throw new CorruptedDataException("Unexpected mark in sequence: " + mark); throw new CorruptDataException("Unexpected mark in sequence: " + mark);
} }
@ -411,7 +411,7 @@ public class IonInput {
} }
return filled; return filled;
} catch (final ClassCastException e) { } catch (final ClassCastException e) {
throw new CorruptedDataException("Unexpected element type in sequence.", e); throw new CorruptDataException("Unexpected element type in sequence.", e);
} }
} }
@ -448,7 +448,7 @@ public class IonInput {
} }
return filled; return filled;
} catch (final ClassCastException e) { } catch (final ClassCastException e) {
throw new CorruptedDataException("Unexpected element type in map.", e); throw new CorruptDataException("Unexpected element type in map.", e);
} }
} }
} }

@ -619,6 +619,19 @@ public class Calc {
* @return picked element * @return picked element
*/ */
public static <T> T pick(List<T> list) public static <T> T pick(List<T> list)
{
return pick(rand, list);
}
/**
* Pick random element from a given list.
*
* @param rand RNG
* @param list list of choices
* @return picked element
*/
public static <T> T pick(Random rand, List<T> list)
{ {
if (list.size() == 0) return null; if (list.size() == 0) return null;
return list.get(rand.nextInt(list.size())); return list.get(rand.nextInt(list.size()));
@ -718,4 +731,14 @@ public class Calc {
return out; return out;
} }
public static int countBits(byte b)
{
int c = 0;
for (int i = 0; i < 8; i++) {
c += (b >> i) & 1;
}
return c;
}
} }

@ -1,6 +1,9 @@
package mightypork.gamecore.util.math; package mightypork.gamecore.util.math;
import java.util.Random;
/** /**
* Numeric range, able to generate random numbers and give min/max values. * Numeric range, able to generate random numbers and give min/max values.
* *
@ -71,7 +74,7 @@ public class Range {
*/ */
public int randInt() public int randInt()
{ {
return Calc.randInt(Calc.rand, (int) Math.round(min), (int) Math.round(min)); return randInt(Calc.rand);
} }
@ -82,7 +85,31 @@ public class Range {
*/ */
public double randDouble() public double randDouble()
{ {
return min + Calc.rand.nextDouble() * (max - min); return randDouble(Calc.rand);
}
/**
* Get random integer from range
*
* @param rand RNG
* @return random int
*/
public int randInt(Random rand)
{
return Calc.randInt(rand, (int) Math.round(min), (int) Math.round(min));
}
/**
* Get random double from this range
*
* @param rand RNG
* @return random double
*/
public double randDouble(Random rand)
{
return min + rand.nextDouble() * (max - min);
} }

@ -87,7 +87,7 @@ public class Coord implements IonObjBundled, IonObjBinary {
} }
public Coord add(Step added) public Coord add(Move added)
{ {
return add(added.x(), added.y()); return add(added.x(), added.y());
} }

@ -16,18 +16,18 @@ import mightypork.gamecore.util.ion.IonOutput;
* *
* @author MightyPork * @author MightyPork
*/ */
public class Step implements IonObjBinary, IonObjBundled { public class Move implements IonObjBinary, IonObjBundled {
public static final int ION_MARK = 254; public static final int ION_MARK = 254;
public static final Step NORTH = new Step(0, -1); public static final Move NORTH = new Move(0, -1);
public static final Step SOUTH = new Step(0, 1); public static final Move SOUTH = new Move(0, 1);
public static final Step EAST = new Step(1, 0); public static final Move EAST = new Move(1, 0);
public static final Step WEST = new Step(-1, 0); public static final Move WEST = new Move(-1, 0);
public static final Step NONE = new Step(0, 0); public static final Move NONE = new Move(0, 0);
public static Step make(int x, int y) public static Move make(int x, int y)
{ {
x = x < 0 ? -1 : x > 0 ? 1 : 0; x = x < 0 ? -1 : x > 0 ? 1 : 0;
y = y < 0 ? -1 : y > 0 ? 1 : 0; y = y < 0 ? -1 : y > 0 ? 1 : 0;
@ -38,20 +38,20 @@ public class Step implements IonObjBinary, IonObjBundled {
if (x == 1 && y == 0) return EAST; if (x == 1 && y == 0) return EAST;
if (x == 0 && y == 0) return NONE; if (x == 0 && y == 0) return NONE;
return new Step(x, y); return new Move(x, y);
} }
private byte x; private byte x;
private byte y; private byte y;
public Step() public Move()
{ {
// for ion // for ion
} }
public Step(int x, int y) public Move(int x, int y)
{ {
this.x = (byte) (x < 0 ? -1 : x > 0 ? 1 : 0); this.x = (byte) (x < 0 ? -1 : x > 0 ? 1 : 0);
this.y = (byte) (y < 0 ? -1 : y > 0 ? 1 : 0); this.y = (byte) (y < 0 ? -1 : y > 0 ? 1 : 0);

@ -0,0 +1,95 @@
package mightypork.gamecore.util.math.algo;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import mightypork.gamecore.util.math.Calc;
/**
* Move lists, bit masks and other utilities
*
* @author MightyPork
*/
public class Moves {
public static final byte BIT_NW = (byte) 0b10000000;
public static final byte BIT_N = (byte) 0b01000000;
public static final byte BIT_NE = (byte) 0b00100000;
public static final byte BIT_E = (byte) 0b00010000;
public static final byte BIT_SE = (byte) 0b00001000;
public static final byte BIT_S = (byte) 0b00000100;
public static final byte BIT_SW = (byte) 0b00000010;
public static final byte BIT_W = (byte) 0b00000001;
public static final byte BITS_CARDINAL = BIT_N | BIT_S | BIT_E | BIT_W;
public static final byte BITS_DIAGONAL = BIT_NE | BIT_NW | BIT_SE | BIT_SW;
public static final byte BITS_NW_CORNER = BIT_W | BIT_NW | BIT_N;
public static final byte BITS_NE_CORNER = BIT_E | BIT_NE | BIT_N;
public static final byte BITS_SW_CORNER = BIT_W | BIT_SW | BIT_S;
public static final byte BITS_SE_CORNER = BIT_E | BIT_SE | BIT_S;
public static final Move NW = Move.make(-1, -1);
public static final Move N = Move.make(0, -1);
public static final Move NE = Move.make(1, -1);
public static final Move E = Move.make(1, 0);
public static final Move SE = Move.make(1, 1);
public static final Move S = Move.make(0, 1);
public static final Move SW = Move.make(-1, 1);
public static final Move W = Move.make(-1, 0);
//@formatter:off
/** All sides, in the order of bits. */
public final static List<Move> ALL_SIDES = Collections.unmodifiableList(Arrays.asList(
NW,
N,
NE,
E,
SE,
S,
SW,
W
));
public final static List<Move> CARDINAL_SIDES = Collections.unmodifiableList(Arrays.asList(
N,
E,
S,
W
));
//@formatter:on
/**
* Get element from all sides
*
* @param i side index
* @return the side coord
*/
public static Move getSide(int i)
{
return ALL_SIDES.get(i);
}
public static byte getBit(int i)
{
return (byte) (1 << (7 - i));
}
public static Move randomCardinal()
{
return Calc.pick(CARDINAL_SIDES);
}
public static Move randomCardinal(Random rand)
{
return Calc.pick(rand, CARDINAL_SIDES);
}
}

@ -1,79 +0,0 @@
package mightypork.gamecore.util.math.algo;
import mightypork.gamecore.util.math.Calc;
public class Sides {
public static final byte MASK_NW = (byte) 0b10000000;
public static final byte MASK_N = (byte) 0b01000000;
public static final byte MASK_NE = (byte) 0b00100000;
public static final byte MASK_E = (byte) 0b00010000;
public static final byte MASK_SE = (byte) 0b00001000;
public static final byte MASK_S = (byte) 0b00000100;
public static final byte MASK_SW = (byte) 0b00000010;
public static final byte MASK_W = (byte) 0b00000001;
public static final byte MASK_CARDINAL = MASK_N | MASK_S | MASK_E | MASK_W;
public static final byte MASK_DIAGONAL = MASK_NE | MASK_NW | MASK_SE | MASK_SW;
public static final byte NW_CORNER = MASK_W | MASK_NW | MASK_N;
public static final byte NE_CORNER = MASK_E | MASK_NE | MASK_N;
public static final byte SW_CORNER = MASK_W | MASK_SW | MASK_S;
public static final byte SE_CORNER = MASK_E | MASK_SE | MASK_S;
public static final Step NW = Step.make(-1, -1);
public static final Step N = Step.make(0, -1);
public static final Step NE = Step.make(1, -1);
public static final Step E = Step.make(1, 0);
public static final Step SE = Step.make(1, 1);
public static final Step S = Step.make(0, 1);
public static final Step SW = Step.make(-1, 1);
public static final Step W = Step.make(-1, 0);
//@formatter:off
/** All sides, in the order of bits. */
public final static Step[] ALL_SIDES = {
NW,
N,
NE,
E,
SE,
S,
SW,
W
};
public final static Step[] CARDINAL_SIDES = {
N,
E,
S,
W
};
//@formatter:on
/**
* Get element from all sides
*
* @param i side index
* @return the side coord
*/
public static Step get(int i)
{
return ALL_SIDES[i];
}
public static byte bit(int i)
{
return (byte) (1 << (7 - i));
}
public static Step randomCardinal()
{
return CARDINAL_SIDES[Calc.randInt(0, 3)];
}
}

@ -3,10 +3,11 @@ package mightypork.gamecore.util.math.algo.floodfill;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Queue; import java.util.Queue;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
public abstract class FloodFill { public abstract class FloodFill {
@ -17,7 +18,7 @@ public abstract class FloodFill {
public abstract boolean canSpreadFrom(Coord pos); public abstract boolean canSpreadFrom(Coord pos);
public abstract Step[] getSpreadSides(); public abstract List<Move> getSpreadSides();
/** /**
@ -49,7 +50,6 @@ public abstract class FloodFill {
activeNodes.add(start); activeNodes.add(start);
final Step[] sides = getSpreadSides();
boolean forceSpreadNext = forceSpreadStart(); boolean forceSpreadNext = forceSpreadStart();
boolean limitReached = false; boolean limitReached = false;
@ -62,7 +62,7 @@ public abstract class FloodFill {
forceSpreadNext = false; forceSpreadNext = false;
for (final Step spr : sides) { for (final Move spr : getSpreadSides()) {
final Coord next = current.add(spr); final Coord next = current.add(spr);
if (activeNodes.contains(next) || foundNodes.contains(next)) continue; if (activeNodes.contains(next) || foundNodes.contains(next)) continue;

@ -8,7 +8,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.algo.pathfinding.heuristics.DiagonalHeuristic; import mightypork.gamecore.util.math.algo.pathfinding.heuristics.DiagonalHeuristic;
import mightypork.gamecore.util.math.algo.pathfinding.heuristics.ManhattanHeuristic; import mightypork.gamecore.util.math.algo.pathfinding.heuristics.ManhattanHeuristic;
@ -29,24 +29,24 @@ public abstract class PathFinder {
private boolean ignoreEnd; private boolean ignoreEnd;
public List<Step> findPathRelative(Coord start, Coord end) public List<Move> findPathRelative(Coord start, Coord end)
{ {
return findPathRelative(start, end, ignoreStart, ignoreEnd); return findPathRelative(start, end, ignoreStart, ignoreEnd);
} }
public List<Step> findPathRelative(Coord start, Coord end, boolean ignoreStart, boolean ignoreEnd) public List<Move> findPathRelative(Coord start, Coord end, boolean ignoreStart, boolean ignoreEnd)
{ {
final List<Coord> path = findPath(start, end, ignoreStart, ignoreEnd); final List<Coord> path = findPath(start, end, ignoreStart, ignoreEnd);
if (path == null) return null; if (path == null) return null;
final List<Step> out = new ArrayList<>(); final List<Move> out = new ArrayList<>();
final Coord current = start.copy(); final Coord current = start.copy();
for (final Coord c : path) { for (final Coord c : path) {
if (c.equals(current)) continue; if (c.equals(current)) continue;
out.add(Step.make(c.x - current.x, c.y - current.y)); out.add(Move.make(c.x - current.x, c.y - current.y));
current.x = c.x; current.x = c.x;
current.y = c.y; current.y = c.y;
} }
@ -76,8 +76,6 @@ public abstract class PathFinder {
open.add(n); open.add(n);
} }
final Step[] walkDirs = getWalkSides();
Node current = null; Node current = null;
while (true) { while (true) {
@ -93,7 +91,7 @@ public abstract class PathFinder {
break; break;
} }
for (final Step go : walkDirs) { for (final Move go : getWalkSides()) {
final Coord c = current.pos.add(go); final Coord c = current.pos.add(go);
if (!isAccessible(c) && !(c.equals(end) && ignoreEnd) && !(c.equals(start) && ignoreStart)) continue; if (!isAccessible(c) && !(c.equals(end) && ignoreEnd) && !(c.equals(start) && ignoreStart)) continue;
@ -225,7 +223,7 @@ public abstract class PathFinder {
protected abstract Heuristic getHeuristic(); protected abstract Heuristic getHeuristic();
protected abstract Step[] getWalkSides(); protected abstract List<Move> getWalkSides();
/** /**

@ -1,8 +1,10 @@
package mightypork.gamecore.util.math.algo.pathfinding; package mightypork.gamecore.util.math.algo.pathfinding;
import java.util.List;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
/** /**
@ -51,7 +53,7 @@ public class PathFinderProxy extends PathFinder {
@Override @Override
protected Step[] getWalkSides() protected List<Move> getWalkSides()
{ {
return source.getWalkSides(); return source.getWalkSides();
} }

@ -9,7 +9,7 @@ import mightypork.gamecore.util.math.color.Color;
* *
* @author MightyPork * @author MightyPork
*/ */
public interface COMMODORE { public interface CMDR {
Color BLACK = Color.fromHex(0x040013); Color BLACK = Color.fromHex(0x040013);
Color WHITE = Color.fromHex(0xFFFFFF); Color WHITE = Color.fromHex(0xFFFFFF);

@ -38,6 +38,7 @@ public class RGB {
public static final Color PINK = Color.fromHex(0xFF3FFC); public static final Color PINK = Color.fromHex(0xFF3FFC);
public static final Color ORANGE = Color.fromHex(0xFC4800); public static final Color ORANGE = Color.fromHex(0xFC4800);
public static final Color BROWN = Color.fromHex(0x83501B);
public static final Color NONE = Color.rgba(0, 0, 0, 0); public static final Color NONE = Color.rgba(0, 0, 0, 0);
} }

@ -1,50 +0,0 @@
package mightypork.gamecore.util.objects;
import java.util.ArrayList;
import java.util.List;
import mightypork.gamecore.logging.Log;
/**
* Object utils class
*
* @author MightyPork
*/
public class ObjectUtils {
public static Object fallback(Object... options)
{
for (final Object o : options) {
if (o != null) return o;
}
return null; // error
}
public static <T> String arrayToString(T[] arr)
{
final StringBuilder sb = new StringBuilder();
sb.append('[');
final boolean first = true;
for (final T o : arr) {
if (!first) sb.append(',');
sb.append(Log.str(o));
}
sb.append(']');
return sb.toString();
}
public static <T> List<T> arrayToList(T[] objs)
{
final ArrayList<T> list = new ArrayList<>();
for (final T o : objs) {
list.add(o);
}
return list;
}
}

@ -0,0 +1,119 @@
/*
* The Alphanum Algorithm is an improved sorting algorithm for strings
* containing numbers. Instead of sorting numbers in ASCII order like
* a standard sort, this algorithm sorts numbers in numeric order.
*
* The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
package mightypork.gamecore.util.strings;
import java.util.Comparator;
/**
* String comparator taking care of strings with numbers.
*
* @author Daniel Migowski
* @author Andre Bogus
* @author David Koelle
* @author MightyPork
*/
public class AlphanumComparator implements Comparator<String> {
public static final AlphanumComparator instance = new AlphanumComparator();
private final boolean isDigit(char ch)
{
return ch >= '0' && ch <= '9';
}
/**
* Length of string is passed in for improved efficiency (only need to
* calculate it once)
**/
private final String getChunk(String s, int slength, int marker)
{
final StringBuilder chunk = new StringBuilder();
char c = s.charAt(marker);
chunk.append(c);
marker++;
if (isDigit(c)) {
while (marker < slength) {
c = s.charAt(marker);
if (!isDigit(c)) break;
chunk.append(c);
marker++;
}
} else {
while (marker < slength) {
c = s.charAt(marker);
if (isDigit(c)) break;
chunk.append(c);
marker++;
}
}
return chunk.toString();
}
@Override
public int compare(String s1, String s2)
{
int thisMarker = 0;
int thatMarker = 0;
final int s1Length = s1.length();
final int s2Length = s2.length();
while (thisMarker < s1Length && thatMarker < s2Length) {
final String thisChunk = getChunk(s1, s1Length, thisMarker);
thisMarker += thisChunk.length();
final String thatChunk = getChunk(s2, s2Length, thatMarker);
thatMarker += thatChunk.length();
// If both chunks contain numeric characters, sort them numerically
int result = 0;
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {
// Simple chunk comparison by length.
final int thisChunkLength = thisChunk.length();
result = thisChunkLength - thatChunk.length();
// If equal, the first different number counts
if (result == 0) {
for (int i = 0; i < thisChunkLength; i++) {
result = thisChunk.charAt(i) - thatChunk.charAt(i);
if (result != 0) {
return result;
}
}
}
} else {
result = thisChunk.compareTo(thatChunk);
}
if (result != 0) return result;
}
return s1Length - s2Length;
}
}

@ -50,7 +50,7 @@ public final class GameLoop extends MainLoop implements ActionRequest.Listener {
@Override @Override
public void execute() public void execute()
{ {
Res.getEffect("gui.shutter").play(1); Res.getSoundEffect("gui.shutter").play(1);
Utils.runAsThread(new TaskTakeScreenshot()); Utils.runAsThread(new TaskTakeScreenshot());
} }
}; };

@ -60,9 +60,8 @@ public final class Res {
fonts.loadFont("tinyutf", font = new DeferredFont("/res/font/TinyUnicode2.ttf", Glyphs.basic, 16)); fonts.loadFont("tinyutf", font = new DeferredFont("/res/font/TinyUnicode2.ttf", Glyphs.basic, 16));
font.setDiscardRatio(6 / 16D, 2 / 16D); font.setDiscardRatio(6 / 16D, 2 / 16D);
// aliases based on concrete usage // aliases
fonts.addAlias("thick", "press_start"); fonts.addAlias("thick", "press_start");
fonts.addAlias("thin", "battlenet"); fonts.addAlias("thin", "battlenet");
fonts.addAlias("tiny", "tinyutf"); fonts.addAlias("tiny", "tinyutf");
} }
@ -135,6 +134,8 @@ public final class Res {
textures.add("tile.brick.passage", grid.makeSheet(3, 2, 4, 1)); textures.add("tile.brick.passage", grid.makeSheet(3, 2, 4, 1));
textures.add("tile.brick.stairs.up", grid.makeQuad(0, 6)); textures.add("tile.brick.stairs.up", grid.makeQuad(0, 6));
textures.add("tile.brick.stairs.down", grid.makeQuad(1, 6)); textures.add("tile.brick.stairs.down", grid.makeQuad(1, 6));
textures.add("tile.extra.chest.closed", grid.makeQuad(0, 4));
textures.add("tile.extra.chest.open", grid.makeQuad(1, 4));
// shadows // shadows
textures.add("tile.shadow.n", grid.makeQuad(0, 7)); textures.add("tile.shadow.n", grid.makeQuad(0, 7));
@ -165,12 +166,14 @@ public final class Res {
textures.add("item.meat", grid.makeQuad(0, 0)); textures.add("item.meat", grid.makeQuad(0, 0));
textures.add("item.club", grid.makeQuad(1, 0)); textures.add("item.club", grid.makeQuad(1, 0));
textures.add("item.sword", grid.makeQuad(2, 0)); textures.add("item.sword", grid.makeQuad(2, 0));
textures.add("item.hammer", grid.makeQuad(3, 0)); textures.add("item.axe", grid.makeQuad(3, 0));
textures.add("item.stone", grid.makeQuad(4, 0)); textures.add("item.stone", grid.makeQuad(4, 0));
textures.add("item.bone", grid.makeQuad(5, 0)); textures.add("item.bone", grid.makeQuad(5, 0));
textures.add("item.cheese", grid.makeQuad(6, 0)); textures.add("item.cheese", grid.makeQuad(6, 0));
textures.add("item.sandwich", grid.makeQuad(7, 0)); textures.add("item.sandwich", grid.makeQuad(7, 0));
textures.add("item.heart_piece", grid.makeQuad(0, 1)); textures.add("item.heart_piece", grid.makeQuad(0, 1));
textures.add("item.knife", grid.makeQuad(1, 1));
textures.add("item.twig", grid.makeQuad(2, 1));
} }
@ -192,7 +195,7 @@ public final class Res {
* @param key * @param key
* @return sheet * @return sheet
*/ */
public static TxSheet txs(String key) public static TxSheet getTxSheet(String key)
{ {
return textures.getSheet(key); return textures.getSheet(key);
} }
@ -204,19 +207,19 @@ public final class Res {
* @param key * @param key
* @return quad * @return quad
*/ */
public static TxQuad txq(String key) public static TxQuad getTxQuad(String key)
{ {
return textures.getQuad(key); return textures.getQuad(key);
} }
public static LoopPlayer getLoop(String key) public static LoopPlayer getSoundLoop(String key)
{ {
return sounds.getLoop(key); return sounds.getLoop(key);
} }
public static EffectPlayer getEffect(String key) public static EffectPlayer getSoundEffect(String key)
{ {
return sounds.getEffect(key); return sounds.getEffect(key);
} }

@ -84,9 +84,9 @@ public class HudLayer extends ScreenLayer {
final HeartBar hearts = new HeartBar( final HeartBar hearts = new HeartBar(
playerHealthTotal, playerHealthTotal,
playerHealthActive, playerHealthActive,
Res.txq("hud.heart.on"), Res.getTxQuad("hud.heart.on"),
Res.txq("hud.heart.half"), Res.getTxQuad("hud.heart.half"),
Res.txq("hud.heart.off"), Res.getTxQuad("hud.heart.off"),
AlignX.LEFT); AlignX.LEFT);
//@formatter:on //@formatter:on
@ -117,13 +117,13 @@ public class HudLayer extends ScreenLayer {
NavButton btn; NavButton btn;
nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.inventory"))); nav.addRight(btn = new NavButton(Res.getTxQuad("nav.button.fg.inventory")));
btn.setAction(gameScreen.actionToggleInv); btn.setAction(gameScreen.actionToggleInv);
nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.eat"))); nav.addRight(btn = new NavButton(Res.getTxQuad("nav.button.fg.eat")));
btn.setAction(gameScreen.actionEat); btn.setAction(gameScreen.actionEat);
nav.addRight(btn = new NavButton(Res.txq("nav.button.fg.pause"))); nav.addRight(btn = new NavButton(Res.getTxQuad("nav.button.fg.pause")));
btn.setAction(gameScreen.actionTogglePause); btn.setAction(gameScreen.actionTogglePause);
@ -131,19 +131,19 @@ public class HudLayer extends ScreenLayer {
//nav.addLeft(new NavButton(Res.txq("nav.button.fg.options"))); //nav.addLeft(new NavButton(Res.txq("nav.button.fg.options")));
//nav.addLeft(new NavButton(Res.txq("nav.button.fg.help"))); //nav.addLeft(new NavButton(Res.txq("nav.button.fg.help")));
nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.menu"))); nav.addLeft(btn = new NavButton(Res.getTxQuad("nav.button.fg.menu")));
btn.setAction(gameScreen.actionMenu); btn.setAction(gameScreen.actionMenu);
nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.save"))); nav.addLeft(btn = new NavButton(Res.getTxQuad("nav.button.fg.save")));
btn.setAction(gameScreen.actionSave); btn.setAction(gameScreen.actionSave);
nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.load"))); nav.addLeft(btn = new NavButton(Res.getTxQuad("nav.button.fg.load")));
btn.setAction(gameScreen.actionLoad); btn.setAction(gameScreen.actionLoad);
nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.map"))); nav.addLeft(btn = new NavButton(Res.getTxQuad("nav.button.fg.map")));
btn.setAction(gameScreen.actionToggleMinimap); btn.setAction(gameScreen.actionToggleMinimap);
nav.addLeft(btn = new NavButton(Res.txq("nav.button.fg.magnify"))); nav.addLeft(btn = new NavButton(Res.getTxQuad("nav.button.fg.magnify")));
btn.setAction(gameScreen.actionToggleZoom); btn.setAction(gameScreen.actionToggleZoom);
} }

@ -43,7 +43,7 @@ public class IngameNav extends LayoutComponent {
paintHelper = leftEdge().growRight(height().mul(4)); paintHelper = leftEdge().growRight(height().mul(4));
bg = Res.txq("nav.bg"); bg = Res.getTxQuad("nav.bg");
} }

@ -50,8 +50,8 @@ public class InvSlot extends ClickableComponent {
public InvSlot(int index, InvSlot[] allSlots) public InvSlot(int index, InvSlot[] allSlots)
{ {
super(); super();
this.txBase = Res.txq("inv.slot.base"); this.txBase = Res.getTxQuad("inv.slot.base");
this.txSelected = Res.txq("inv.slot.selected"); this.txSelected = Res.getTxQuad("inv.slot.selected");
this.index = index; this.index = index;
this.slots = allSlots; this.slots = allSlots;

@ -22,7 +22,7 @@ import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.ItemType; import mightypork.rogue.world.item.ItemType;
public class InvLayer extends ScreenLayer { public class InventoryLayer extends ScreenLayer {
private static final int SLOT_COUNT = 8; private static final int SLOT_COUNT = 8;
private static final int SLOT_ROW = 4; private static final int SLOT_ROW = 4;
@ -86,7 +86,7 @@ public class InvLayer extends ScreenLayer {
} }
public InvLayer(final ScreenGame screen) public InventoryLayer(final ScreenGame screen)
{ {
super(screen); super(screen);
@ -200,17 +200,7 @@ public class InvLayer extends ScreenLayer {
final int selected = getSelectedSlot(); final int selected = getSelectedSlot();
if (selected != -1) { if (selected != -1) {
final PlayerFacade pl = WorldProvider.get().getPlayer(); WorldProvider.get().getPlayer().dropItem(selected);
final Item itm = pl.getInventory().getItem(selected);
if (itm != null && !itm.isEmpty()) {
final Item piece = itm.split(1);
if (itm.isEmpty()) pl.getInventory().setItem(selected, null);
if (!pl.getLevel().getTile(pl.getCoord()).dropItem(piece)) {
pl.getInventory().addItem(piece); // add back
}
}
} }
} }
}); });

@ -20,9 +20,9 @@ public class NavButton extends ClickableComponent {
public NavButton(TxQuad fg) public NavButton(TxQuad fg)
{ {
super(); super();
this.base = Res.txq("nav.button.bg.base"); this.base = Res.getTxQuad("nav.button.bg.base");
this.hover = Res.txq("nav.button.bg.hover"); this.hover = Res.getTxQuad("nav.button.bg.hover");
this.down = Res.txq("nav.button.bg.down"); this.down = Res.getTxQuad("nav.button.bg.down");
this.fg = fg; this.fg = fg;
} }

@ -10,7 +10,6 @@ import mightypork.gamecore.gui.screens.LayeredScreen;
import mightypork.gamecore.input.KeyStroke; import mightypork.gamecore.input.KeyStroke;
import mightypork.gamecore.input.Keys; import mightypork.gamecore.input.Keys;
import mightypork.gamecore.logging.Log; import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.math.Calc;
import mightypork.rogue.Config; import mightypork.rogue.Config;
import mightypork.rogue.GameStateManager.GameState; import mightypork.rogue.GameStateManager.GameState;
import mightypork.rogue.events.GameStateRequest; import mightypork.rogue.events.GameStateRequest;
@ -32,7 +31,7 @@ public class ScreenGame extends LayeredScreen {
WORLD, INV; WORLD, INV;
} }
private InvLayer invLayer; private InventoryLayer invLayer;
private HudLayer hudLayer; private HudLayer hudLayer;
private WorldLayer worldLayer; private WorldLayer worldLayer;
@ -131,6 +130,17 @@ public class ScreenGame extends LayeredScreen {
} }
}; };
public Action actionDropLastPickedItem = new Action() {
@Override
public void execute()
{
final PlayerFacade pl = WorldProvider.get().getPlayer();
if (pl.isDead() || pl.getWorld().isPaused()) return;
pl.dropItem(pl.getInventory().getLastAddIndex());
}
};
/** /**
* Set gui state (overlay) * Set gui state (overlay)
@ -175,7 +185,7 @@ public class ScreenGame extends LayeredScreen {
{ {
super(app); super(app);
addLayer(invLayer = new InvLayer(this)); addLayer(invLayer = new InventoryLayer(this));
invLayer.setEnabled(false); invLayer.setEnabled(false);
invLayer.setVisible(false); invLayer.setVisible(false);
@ -187,29 +197,18 @@ public class ScreenGame extends LayeredScreen {
worldLayer.setEnabled(true); worldLayer.setEnabled(true);
worldLayer.setVisible(true); worldLayer.setVisible(true);
// TODO temporary, remove
bindKey(new KeyStroke(Keys.N, Keys.MOD_CONTROL), new Runnable() {
@Override
public void run()
{
WorldProvider.get().createWorld(Calc.rand.nextLong());
}
});
//pause key //pause key
bindKey(new KeyStroke(Keys.P), actionTogglePause); bindKey(new KeyStroke(Keys.P), actionTogglePause);
bindKey(new KeyStroke(Keys.PAUSE), actionTogglePause); bindKey(new KeyStroke(Keys.PAUSE), actionTogglePause);
bindKey(new KeyStroke(Keys.SPACE), actionTogglePause); bindKey(new KeyStroke(Keys.SPACE), actionTogglePause);
bindKey(new KeyStroke(Keys.I), actionToggleInv); bindKey(new KeyStroke(Keys.I), actionToggleInv);
bindKey(new KeyStroke(Keys.D), actionDropLastPickedItem);
bindKey(new KeyStroke(Keys.E), actionEat); bindKey(new KeyStroke(Keys.E), actionEat);
bindKey(new KeyStroke(Keys.M), actionToggleMinimap); bindKey(new KeyStroke(Keys.M), actionToggleMinimap);
bindKey(new KeyStroke(Keys.Z), actionToggleZoom); bindKey(new KeyStroke(Keys.Z), actionToggleZoom);
bindKey(new KeyStroke(Keys.R, Keys.MOD_CONTROL), actionLoad);
bindKey(new KeyStroke(Keys.L, Keys.MOD_CONTROL), actionLoad); bindKey(new KeyStroke(Keys.L, Keys.MOD_CONTROL), actionLoad);
bindKey(new KeyStroke(Keys.S, Keys.MOD_CONTROL), actionSave); bindKey(new KeyStroke(Keys.S, Keys.MOD_CONTROL), actionSave);
// add as actions - enableables. // add as actions - enableables.
@ -224,11 +223,12 @@ public class ScreenGame extends LayeredScreen {
worldActions.add(actionSave); worldActions.add(actionSave);
worldActions.add(actionLoad); worldActions.add(actionLoad);
worldActions.add(actionMenu); worldActions.add(actionMenu);
worldActions.add(actionDropLastPickedItem);
worldActions.setEnabled(true); worldActions.setEnabled(true);
// TMP TODO remove // CHEAT - X-ray
bindKey(new KeyStroke(Keys.X), new Runnable() { bindKey(new KeyStroke(Keys.F10, Keys.MOD_CONTROL), new Runnable() {
@Override @Override
public void run() public void run()

@ -69,7 +69,7 @@ public class WorldConsoleRenderer extends BaseComponent {
} }
} catch (final ConcurrentModificationException e) { } catch (final ConcurrentModificationException e) {
Log.e(e); // this should not happen anymore Log.e(e); // this should not happen
} }

@ -64,7 +64,7 @@ public class ScreenMainMenu extends LayeredScreen {
root.add(layout); root.add(layout);
int r = 0; int r = 0;
final ImagePainter ip = new ImagePainter(Res.txq("logo")); final ImagePainter ip = new ImagePainter(Res.getTxQuad("logo"));
ip.keepAspectRatio(); ip.keepAspectRatio();
layout.put(ip, r, 0, 4, 1); layout.put(ip, r, 0, 4, 1);
r += 5; r += 5;

@ -162,6 +162,7 @@ public class WorldSlot extends ConstraintLayout {
if (!file.exists()) { if (!file.exists()) {
label = "<empty>"; label = "<empty>";
worldBundle = null;
} else { } else {
try { try {
worldBundle = Ion.fromFile(file); worldBundle = Ion.fromFile(file);
@ -173,7 +174,8 @@ public class WorldSlot extends ConstraintLayout {
delBtn.setVisible(true); delBtn.setVisible(true);
delBtn.setEnabled(true); delBtn.setEnabled(true);
} catch (final IOException e) { } catch (final Exception e) {
Log.w("Error loading world save.", e);
label = "<corrupt>"; label = "<corrupt>";
} }
} }

@ -14,6 +14,7 @@ public class Inventory implements IonObjBinary {
public static final short ION_MARK = 54; public static final short ION_MARK = 54;
private Item[] items; private Item[] items;
private int lastAddIndex = 0;
public Inventory(int size) public Inventory(int size)
@ -87,6 +88,8 @@ public class Inventory implements IonObjBinary {
*/ */
public Item getItem(int i) public Item getItem(int i)
{ {
if (i < 0 || i > getSize()) return null;
verifyIndex(i); verifyIndex(i);
final Item itm = items[i]; final Item itm = items[i];
if (itm == null || itm.isEmpty()) return null; if (itm == null || itm.isEmpty()) return null;
@ -112,6 +115,7 @@ public class Inventory implements IonObjBinary {
{ {
verifyIndex(i); verifyIndex(i);
items[i] = item; items[i] = item;
lastAddIndex = i;
} }
@ -136,7 +140,10 @@ public class Inventory implements IonObjBinary {
for (int i = 0; i < getSize(); i++) { for (int i = 0; i < getSize(); i++) {
final Item itm = getItem(i); final Item itm = getItem(i);
if (itm != null) { if (itm != null) {
if (itm.addItem(stored)) return true; if (itm.addItem(stored)) {
lastAddIndex = i;
return true;
}
} }
} }
@ -145,6 +152,7 @@ public class Inventory implements IonObjBinary {
final Item itm = getItem(i); final Item itm = getItem(i);
if (itm == null) { if (itm == null) {
setItem(i, stored.split(stored.getAmount())); // store a copy, empty the original item. setItem(i, stored.split(stored.getAmount())); // store a copy, empty the original item.
lastAddIndex = i;
return true; return true;
} }
} }
@ -167,6 +175,12 @@ public class Inventory implements IonObjBinary {
} }
public int getLastAddIndex()
{
return lastAddIndex;
}
@Override @Override
public String toString() public String toString()
{ {

@ -5,7 +5,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityType; import mightypork.rogue.world.entity.EntityType;
@ -50,25 +50,25 @@ public abstract class PlayerControl {
public void goNorth() public void goNorth()
{ {
go(Step.NORTH); go(Move.NORTH);
} }
public void goSouth() public void goSouth()
{ {
go(Step.SOUTH); go(Move.SOUTH);
} }
public void goEast() public void goEast()
{ {
go(Step.EAST); go(Move.EAST);
} }
public void goWest() public void goWest()
{ {
go(Step.WEST); go(Move.WEST);
} }
@ -85,7 +85,7 @@ public abstract class PlayerControl {
} }
public boolean canGo(Step side) public boolean canGo(Move side)
{ {
return getPlayer().canGoTo(side); return getPlayer().canGoTo(side);
} }
@ -97,7 +97,7 @@ public abstract class PlayerControl {
* @param side * @param side
* @return * @return
*/ */
public boolean clickTile(Step side) public boolean clickTile(Move side)
{ {
return doClickTile(getPlayer().getCoord().add(side).toVect()); return doClickTile(getPlayer().getCoord().add(side).toVect());
} }
@ -132,14 +132,14 @@ public abstract class PlayerControl {
} }
public void go(Step side) public void go(Move side)
{ {
getPlayer().cancelPath(); getPlayer().cancelPath();
getPlayer().addPathStep(side); getPlayer().addPathStep(side);
} }
public boolean tryGo(Step e) public boolean tryGo(Move e)
{ {
if (!canGo(e)) return false; if (!canGo(e)) return false;
go(e); go(e);

@ -7,7 +7,7 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
@ -158,7 +158,7 @@ public class PlayerFacade {
} }
public void addPathStep(Step step) public void addPathStep(Move step)
{ {
world.playerEntity.pos.addStep(step); world.playerEntity.pos.addStep(step);
} }
@ -400,8 +400,32 @@ public class PlayerFacade {
} }
public boolean canGoTo(Step side) public boolean canGoTo(Move side)
{ {
return getEntity().pos.canGoTo(side); return getEntity().pos.canGoTo(side);
} }
public void dropItem(int itemIndex)
{
final Item itm = getInventory().getItem(itemIndex);
if (itm != null && !itm.isEmpty()) {
final Item piece = itm.split(1);
getInventory().clean();
Coord dropPos;
if (world.playerEntity.pos.isMoving()) {
dropPos = world.playerEntity.pos.getLastPos();
} else {
dropPos = getCoord();
}
if (!getLevel().getTile(dropPos).dropItem(piece)) {
getInventory().addItem(piece); // add back
} else {
world.getConsole().msgDroppedItem(piece);
}
}
}
} }

@ -129,7 +129,7 @@ public class WorldConsole implements Updateable {
public void msgDie(Entity attacker) public void msgDie(Entity attacker)
{ {
addMessage("You've been defeated by a " + attacker.getVisualName() + "!"); addMessage("You've been defeated by " + addArticle(attacker.getVisualName()) + "!");
} }
@ -141,7 +141,7 @@ public class WorldConsole implements Updateable {
public void msgEat(Item item) public void msgEat(Item item)
{ {
addMessage("You've eaten a " + item.getVisualName() + "."); addMessage("You've eaten " + addArticle(item.getVisualName()) + ".");
} }
@ -153,7 +153,7 @@ public class WorldConsole implements Updateable {
public void msgEquipWeapon(Item item) public void msgEquipWeapon(Item item)
{ {
addMessage("You're now wielding " + (item == null ? "NOTHING" : "a " + item.getVisualName()) + "."); addMessage("You're now wielding " + (item == null ? "NOTHING" : addArticle(item.getVisualName())) + ".");
} }
@ -165,7 +165,7 @@ public class WorldConsole implements Updateable {
public void msgKill(Entity prey) public void msgKill(Entity prey)
{ {
addMessage("You've killed a " + prey.getVisualName() + "."); addMessage("You've killed " + addArticle(prey.getVisualName()) + ".");
} }
@ -183,12 +183,19 @@ public class WorldConsole implements Updateable {
public void msgPick(Item item) public void msgPick(Item item)
{ {
addMessage("You've picked up a " + item.getVisualName() + "."); addMessage("You've picked up " + addArticle(item.getVisualName()) + ".");
lastPickupItem = item; lastPickupItem = item;
timeSinceLastPickup = 0; timeSinceLastPickup = 0;
} }
public void msgDroppedItem(Item item)
{
addMessage("You've dropped " + addArticle(item.getVisualName()) + ".");
lastPickupItem = null;
}
public void msgWeaponBreak(Item item) public void msgWeaponBreak(Item item)
{ {
addMessage("Your " + item.getVisualName() + " has broken!"); addMessage("Your " + item.getVisualName() + " has broken!");
@ -217,4 +224,26 @@ public class WorldConsole implements Updateable {
{ {
addMessage("Error while loading; See the log for details."); addMessage("Error while loading; See the log for details.");
} }
public void msgOpenChest()
{
addMessage("You've opened a treasure chest!");
}
private String addArticle(String name)
{
switch (Character.toLowerCase(name.charAt(0))) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
case 'y':
return "an " + name;
default:
return "a " + name;
}
}
} }

@ -1,9 +1,11 @@
package mightypork.rogue.world.entity; package mightypork.rogue.world.entity;
import java.util.List;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Moves;
import mightypork.gamecore.util.math.algo.pathfinding.Heuristic; import mightypork.gamecore.util.math.algo.pathfinding.Heuristic;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder; import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
@ -53,9 +55,9 @@ public class EntityPathFinder extends PathFinder {
@Override @Override
public Step[] getWalkSides() public List<Move> getWalkSides()
{ {
return Sides.CARDINAL_SIDES; return Moves.CARDINAL_SIDES;
} }
} }

@ -22,14 +22,14 @@ public class BossRatAi extends GrayRatAi {
{ {
super(entity); super(entity);
setAttackTime(0.7); setAttackTime(0.2);
} }
@Override @Override
protected int getAttackStrength() protected int getAttackStrength()
{ {
return Calc.randInt(5, 11); return Calc.randInt(1, 6);
} }
@ -52,6 +52,6 @@ public class BossRatAi extends GrayRatAi {
@Override @Override
protected double getStepTime() protected double getStepTime()
{ {
return isIdle() ? 0.6 : 0.4; return isIdle() ? 0.6 : 0.37;
} }
} }

@ -8,8 +8,8 @@ import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.ion.IonBundle; import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.math.Calc; import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Moves;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder; import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinderProxy; import mightypork.gamecore.util.math.algo.pathfinding.PathFinderProxy;
import mightypork.rogue.world.entity.AiTimer; import mightypork.rogue.world.entity.AiTimer;
@ -65,7 +65,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
if (entity.pos.isMoving()) return; if (entity.pos.isMoving()) return;
if (Calc.rand.nextInt(10) == 0) { if (Calc.rand.nextInt(10) == 0) {
entity.pos.addStep(Sides.randomCardinal()); entity.pos.addStep(Moves.randomCardinal());
} }
} }
}; };
@ -260,7 +260,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
} }
private List<Step> getPathToPrey(Entity prey) private List<Move> getPathToPrey(Entity prey)
{ {
if (!isPreyValid(prey)) return null; if (!isPreyValid(prey)) return null;
@ -280,7 +280,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
return; return;
} }
final List<Step> preyPath = getPathToPrey(prey); final List<Move> preyPath = getPathToPrey(prey);
if (preyPath == null || preyPath.size() > getPreyAbandonDistance()) { if (preyPath == null || preyPath.size() > getPreyAbandonDistance()) {
stopChasing(); stopChasing();

@ -10,7 +10,7 @@ import java.util.Set;
import mightypork.gamecore.util.ion.IonBundle; import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.constraints.vect.VectConst; import mightypork.gamecore.util.math.constraints.vect.VectConst;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.entity.EntityModule; import mightypork.rogue.world.entity.EntityModule;
@ -22,7 +22,7 @@ public class EntityModulePosition extends EntityModule {
private final Coord lastPos = new Coord(0, 0); private final Coord lastPos = new Coord(0, 0);
private boolean walking = false; private boolean walking = false;
private final Queue<Step> path = new LinkedList<>(); private final Queue<Move> path = new LinkedList<>();
private final EntityPos entityPos = new EntityPos(); private final EntityPos entityPos = new EntityPos();
private double stepTime = 0.5; private double stepTime = 0.5;
@ -136,7 +136,7 @@ public class EntityModulePosition extends EntityModule {
walking = true; walking = true;
final Step step = path.poll(); final Move step = path.poll();
final Coord planned = entityPos.getCoord().add(step.toCoord()); final Coord planned = entityPos.getCoord().add(step.toCoord());
@ -177,7 +177,7 @@ public class EntityModulePosition extends EntityModule {
* *
* @param step * @param step
*/ */
public void addStep(Step step) public void addStep(Move step)
{ {
if (path.isEmpty() && !canGoTo(step)) return; if (path.isEmpty() && !canGoTo(step)) return;
@ -203,7 +203,7 @@ public class EntityModulePosition extends EntityModule {
public boolean navigateTo(Coord target) public boolean navigateTo(Coord target)
{ {
if (target.equals(getCoord())) return true; if (target.equals(getCoord())) return true;
final List<Step> newPath = entity.getPathFinder().findPathRelative(entityPos.getCoord(), target); final List<Move> newPath = entity.getPathFinder().findPathRelative(entityPos.getCoord(), target);
if (newPath == null) return false; if (newPath == null) return false;
cancelPath(); cancelPath();
@ -228,7 +228,7 @@ public class EntityModulePosition extends EntityModule {
* *
* @param path steps * @param path steps
*/ */
public void addSteps(List<Step> path) public void addSteps(List<Move> path)
{ {
this.path.addAll(path); this.path.addAll(path);
} }
@ -284,9 +284,15 @@ public class EntityModulePosition extends EntityModule {
} }
public boolean canGoTo(Step side) public boolean canGoTo(Move side)
{ {
return entity.getPathFinder().isAccessible(getCoord().add(side)); return entity.getPathFinder().isAccessible(getCoord().add(side));
} }
public Coord getLastPos()
{
return lastPos;
}
} }

@ -8,7 +8,7 @@ import mightypork.gamecore.util.ion.IonBundle;
import mightypork.gamecore.util.ion.IonObjBundled; import mightypork.gamecore.util.ion.IonObjBundled;
import mightypork.gamecore.util.math.Easing; import mightypork.gamecore.util.math.Easing;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.gamecore.util.math.constraints.vect.VectConst; import mightypork.gamecore.util.math.constraints.vect.VectConst;
import mightypork.gamecore.util.math.constraints.vect.mutable.VectAnimated; import mightypork.gamecore.util.math.constraints.vect.mutable.VectAnimated;
@ -128,7 +128,7 @@ class EntityPos implements IonObjBundled, Updateable {
} }
public void walk(Step step, double secs) public void walk(Move step, double secs)
{ {
setTo(coord.x + step.x(), coord.y + step.y()); setTo(coord.x + step.x(), coord.y + step.y());
walkOffset.setTo(-step.x(), -step.y()); walkOffset.setTo(-step.x(), -step.y());

@ -37,7 +37,7 @@ public class EntityRendererMobLR extends EntityRenderer {
public EntityRendererMobLR(Entity entity, String sheetKey) public EntityRendererMobLR(Entity entity, String sheetKey)
{ {
this.entity = entity; this.entity = entity;
this.sheet = Res.txs(sheetKey); this.sheet = Res.getTxSheet(sheetKey);
} }

@ -0,0 +1,253 @@
package mightypork.rogue.world.gen;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import mightypork.gamecore.util.math.Range;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.level.Level;
public class LevelBuilder {
public static enum BuildOrder
{
FIRST, MIDDLE, LAST
}
private class RoomEntry {
int count;
RoomBuilder room;
boolean important;
public RoomEntry(RoomBuilder room, int count, boolean important)
{
this.count = count;
this.room = room;
this.important = important;
}
}
private class ItemEntry {
Item item;
boolean important;
public ItemEntry(Item item, boolean important)
{
this.item = item;
this.important = important;
}
}
private class EntityEntry {
Entity entity;
boolean important;
public EntityEntry(Entity item, boolean important)
{
this.entity = item;
this.important = important;
}
}
private final ScratchMap map;
private final Random rand;
private boolean built;
private final LinkedList<RoomEntry> roomsFirst = new LinkedList<>();
private final LinkedList<RoomEntry> roomsMiddle = new LinkedList<>();
private final LinkedList<RoomEntry> roomsLast = new LinkedList<>();
private final LinkedList<ItemEntry> items = new LinkedList<>();
private final LinkedList<EntityEntry> entities = new LinkedList<>();
/**
* make a new level builder instance.
*
* @param max_size max map size (square side - tiles)
* @param theme tiles theme
* @param seed level seed
*/
public LevelBuilder(int max_size, MapTheme theme, long seed)
{
this.rand = new Random(seed);
this.map = new ScratchMap(max_size, theme, rand);
}
/**
* Add a single room to the room buffer.
*
* @param room room builder
* @param order build order
* @param important try harder and throw error on fail
*/
public void addRoom(RoomBuilder room, BuildOrder order, boolean important)
{
addRoom(room, Range.make(1, 1), order, important);
}
/**
* Add multiple rooms of the type to the room buffer.
*
* @param room room builder
* @param count number of rooms to build
* @param order build order
* @param important try harder and throw error on fail
*/
public void addRoom(RoomBuilder room, Range count, BuildOrder order, boolean important)
{
final List<RoomEntry> list;
switch (order) {
case FIRST:
list = roomsFirst;
break;
default:
case MIDDLE:
list = roomsMiddle;
break;
case LAST:
list = roomsLast;
break;
}
list.add(new RoomEntry(room, count.randInt(rand), important));
}
private void buildRooms(LinkedList<RoomEntry> list)
{
while (!list.isEmpty()) {
Collections.shuffle(list, rand);
for (final Iterator<RoomEntry> iter = list.iterator(); iter.hasNext();) {
final RoomEntry rge = iter.next();
map.addRoom(rge.room, rge.important);
if ((--rge.count) <= 0) {
iter.remove();
}
}
}
}
private void buildCorridors() throws WorldGenError
{
map.buildCorridors();
}
private void buildEntities()
{
for (final EntityEntry entry : entities) {
final int tries = entry.important ? 200 : 50;
final boolean success = map.addEntityInMap(entry.entity, tries);
if (entry.important && !success) {
throw new WorldGenError("Could not place an important entity: " + entry.entity);
}
}
}
private void buildItems()
{
for (final ItemEntry entry : items) {
final int tries = entry.important ? 200 : 50;
final boolean success = map.addItemInMap(entry.item, tries);
if (entry.important && !success) {
throw new WorldGenError("Could not place an important item: " + entry.item);
}
}
}
private void writeToMap()
{
buildRooms(roomsFirst);
buildRooms(roomsMiddle);
buildRooms(roomsLast);
buildCorridors();
map.fixGlitches();
buildItems();
buildEntities();
}
/**
* Write to a new level instance.
*
* @param world level's world
* @return the level
* @throws WorldGenError on error in generation
*/
public Level build(World world) throws WorldGenError
{
if (built) {
throw new WorldGenError("Level already built.");
}
built = true;
writeToMap();
final Coord size = map.getNeededSize();
final Level lvl = new Level(size.x, size.y);
lvl.setWorld(world); // important for creating entities
map.writeToLevel(lvl);
return lvl;
}
/**
* Add an item to be added to the level when tiles are built.
*
* @param item item to add
* @param important try harder and throw error on fail
* @throws WorldGenError on fail
*/
public void addItem(Item item, boolean important) throws WorldGenError
{
items.add(new ItemEntry(item, important));
}
/**
* Add an entity to be added to the level when tiles are built.<br>
* It's EID will be assigned during writing to level.
*
* @param entity entity to add
* @param important try harder and throw error on fail
* @throws WorldGenError on fail
*/
public void addEntity(Entity entity, boolean important) throws WorldGenError
{
entities.add(new EntityEntry(entity, important));
}
}

@ -1,124 +0,0 @@
package mightypork.rogue.world.gen;
import java.util.Random;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.gen.rooms.Rooms;
import mightypork.rogue.world.gen.themes.ThemeBrick;
import mightypork.rogue.world.item.Items;
import mightypork.rogue.world.level.Level;
public class LevelGenerator {
public static final MapTheme DUNGEON_THEME = new ThemeBrick();
@SuppressWarnings("fallthrough")
public static Level build(World world, long seed, int level, MapTheme theme, boolean lastLevel) throws WorldGenError
{
Log.f3("Generating level of complexity: " + level);
final Random rand = new Random(seed + 13);
final int max_size = 128;
final ScratchMap map = new ScratchMap(max_size, theme, rand);
// start
if (!map.addRoom(Rooms.ENTRANCE, true)) {
throw new WorldGenError("Could not place entrance room.");
}
for (int i = 0; i < Calc.randInt(rand, 1 + level, (int) (1 + level * 1.5)); i++) {
map.addRoom(Rooms.BASIC, false);
// spice it up with dead ends
if (rand.nextInt(6) > 0) map.addRoom(Rooms.DEAD_END, false);
}
for (int i = 0; i < Calc.randInt(rand, 1, (int) Math.ceil(level / 2D)); i++) {
map.addRoom(Rooms.TREASURE, false);
}
if (!lastLevel) {
if (!map.addRoom(Rooms.EXIT, true)) {
throw new WorldGenError("Could not place exit room.");
}
}
if (lastLevel) {
if (!map.addRoom(Rooms.BOSS, true)) {
throw new WorldGenError("Could not place boss room.");
}
}
map.addRoom(Rooms.HEART_ROOM, true);
map.buildCorridors();
switch (level) {
default:
case 3:
case 2:
if (rand.nextInt(2) == 0) map.putItemInMap(Items.CLUB.createItemDamaged(30), 50);
case 1:
if (rand.nextInt(2) == 0) map.putItemInMap(Items.ROCK.createItemDamaged(10), 50);
}
if (level == 1) {
map.putItemInMap(Items.BONE.createItemDamaged(20), 60);
}
if (level == 2) {
map.putItemInMap(Items.CLUB.createItemDamaged(50), 60);
}
if (level == 6) {
map.putItemInMap(Items.SWORD.createItemDamaged(60), 200);
}
if (level == 4) {
map.putItemInMap(Items.HAMMER.createItemDamaged(40), 100);
}
// entities - random rats
for (int i = 0; i < Calc.randInt(rand, 2 + level * 2, 5 + level * 3); i++) {
Entity e;
if (level > 2 && rand.nextInt(level - 2 + 1) != 0) {
e = Entities.RAT_BROWN.createEntity();
} else {
e = Entities.RAT_GRAY.createEntity();
}
map.putEntityInMap(e, 30);
if (rand.nextInt(6 + level / 2) == 0) {
map.putItemInMap(Items.CHEESE.createItem(), 10);
}
if (rand.nextInt(6) == 0) {
map.putItemInMap(Items.MEAT.createItem(), 10);
}
}
final Coord size = map.getNeededSize();
final Level lvl = new Level(size.x, size.y);
lvl.setWorld(world); // important for creating entities
map.writeToLevel(lvl);
return lvl;
}
}

@ -30,4 +30,7 @@ public interface MapTheme {
TileModel exit(); TileModel exit();
TileModel chest();
} }

@ -13,5 +13,5 @@ import mightypork.gamecore.util.math.algo.Coord;
*/ */
public interface RoomBuilder { public interface RoomBuilder {
RoomDesc buildToFit(ScratchMap map, MapTheme theme, Random rand, Coord center) throws WorldGenError; RoomEntry buildRoom(ScratchMap map, MapTheme theme, Random rand, Coord center) throws WorldGenError;
} }

@ -5,17 +5,17 @@ import mightypork.gamecore.util.math.algo.Coord;
/** /**
* Room description * Room description entry for {@link ScratchMap}
* *
* @author MightyPork * @author MightyPork
*/ */
public class RoomDesc { public class RoomEntry {
final Coord min; final Coord min;
final Coord max; final Coord max;
public RoomDesc(Coord min, Coord max) public RoomEntry(Coord min, Coord max)
{ {
super(); super();
this.min = min; this.min = min;

@ -0,0 +1,28 @@
package mightypork.rogue.world.gen;
import mightypork.rogue.world.gen.rooms.*;
import mightypork.rogue.world.item.Item;
public class Rooms {
public static final RoomBuilder BASIC = new BasicRoom();
public static final RoomBuilder STORAGE = new StorageRoom();
public static final RoomBuilder DEAD_END = new DeadEndRoom();
public static final RoomBuilder ENTRANCE = new EntranceRoom();
public static final RoomBuilder EXIT = new ExitRoom();
public static final RoomBuilder BOSS = new BossRoom();
public static RoomBuilder treasure(Item item)
{
return new TreasureChestRoom(item);
}
public static RoomBuilder shrine(Item item)
{
return new ItemShrineRoom(item);
}
}

@ -10,8 +10,8 @@ import java.util.Set;
import mightypork.gamecore.logging.Log; import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.math.Calc; import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Moves;
import mightypork.gamecore.util.math.algo.pathfinding.Heuristic; import mightypork.gamecore.util.math.algo.pathfinding.Heuristic;
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder; import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
@ -33,7 +33,7 @@ public class ScratchMap {
private final int width; private final int width;
private final int height; private final int height;
private final List<RoomDesc> rooms = new ArrayList<>(); private final List<RoomEntry> rooms = new ArrayList<>();
/** Coords to connect with corridors */ /** Coords to connect with corridors */
private final List<Coord> nodes = new ArrayList<>(); private final List<Coord> nodes = new ArrayList<>();
@ -96,9 +96,9 @@ public class ScratchMap {
@Override @Override
public Step[] getWalkSides() public List<Move> getWalkSides()
{ {
return Sides.CARDINAL_SIDES; return Moves.CARDINAL_SIDES;
} }
}; };
@ -136,83 +136,99 @@ public class ScratchMap {
} }
public boolean addRoom(RoomBuilder rb, boolean critical) public void addRoom(RoomBuilder rb, boolean critical) throws WorldGenError
{ {
final Coord center = Coord.make(0, 0); try {
if (rooms.size() > 0) minimizeBounds();
int failed = 0;
int failed_total = 0;
while (true) {
final int sizeX = genMax.x - genMin.x; final Coord roomPos = Coord.make(0, 0);
final int sizeY = genMax.y - genMin.y;
center.x = genMin.x + rand.nextInt(sizeX); int failed = 0;
center.y = genMin.y + rand.nextInt(sizeY); int failed_total = 0;
switch (rand.nextInt(4)) { while (true) {
case 0:
center.x += (failed_total / 35);
break;
case 1:
center.x -= (failed_total / 35);
break;
case 2:
center.y += (failed_total / 35);
break;
case 3:
center.y -= (failed_total / 35);
}
final RoomDesc rd = rb.buildToFit(this, theme, rand, center);
if (rd != null) {
rooms.add(rd);
genMin.x = Math.min(genMin.x, rd.min.x);
genMin.y = Math.min(genMin.y, rd.min.y);
genMax.x = Math.max(genMax.x, rd.max.x); final int sizeX = genMax.x - genMin.x;
genMax.y = Math.max(genMax.y, rd.max.y); final int sizeY = genMax.y - genMin.y;
clampBounds();
nodes.add(center); roomPos.x = genMin.x + rand.nextInt(sizeX + 1);
// Log.f3("Placed room (failed " + failed_total + " x)."); roomPos.y = genMin.y + rand.nextInt(sizeY + 1);
return true; switch (rand.nextInt(4)) {
} else { case 0:
failed++; roomPos.x += (failed_total / 35);
failed_total++; break;
case 1:
if (failed_total > 1000) { roomPos.x -= (failed_total / 35);
return false; break;
case 2:
roomPos.y += (failed_total / 35);
break;
case 3:
roomPos.y -= (failed_total / 35);
} }
if (failed > 300) { final RoomEntry rd = rb.buildRoom(this, theme, rand, roomPos);
Log.w("Faild to build room."); if (rd != null) {
if (critical) {
rooms.add(rd);
genMin.x -= 5;
genMin.y -= 5; genMin.x = Math.min(genMin.x, rd.min.x);
genMax.x += 5; genMin.y = Math.min(genMin.y, rd.min.y);
genMax.y += 5;
clampBounds(); genMax.x = Math.max(genMax.x, rd.max.x);
genMax.y = Math.max(genMax.y, rd.max.y);
failed = 0; clampBounds();
Log.f3("Trying again.");
continue; nodes.add(roomPos);
} else { return;
return false;
} else {
failed++;
failed_total++;
if (failed_total > 1000) {
throw new WorldGenError("Failed to add a room.");
}
if (failed > 300) {
Log.w("Faild to build room.");
if (critical) {
// expand gen bounds
genMin.x -= 5;
genMin.y -= 5;
genMax.x += 5;
genMax.y += 5;
clampBounds();
failed = 0;
Log.f3("Trying again.");
continue;
} else {
throw new WorldGenError("Failed to add a room.");
}
} }
} }
} }
} catch (final WorldGenError e) {
if (!critical) {
Log.w("Could not place a room.", e);
return;
} else {
// rethrow
throw e;
}
} }
} }
/**
* Clamp bounds to available area
*/
private void clampBounds() private void clampBounds()
{ {
genMin.x = Calc.clamp(genMin.x, 0, width - 1); genMin.x = Calc.clamp(genMin.x, 0, width - 1);
@ -222,6 +238,27 @@ public class ScratchMap {
} }
/**
* Minimize gen bounds based on defined room bounds
*/
private void minimizeBounds()
{
final Coord low = Coord.make(width, height);
final Coord high = Coord.make(0, 0);
for (final RoomEntry rd : rooms) {
low.x = Math.min(low.x, rd.min.x);
low.y = Math.min(low.y, rd.min.y);
high.x = Math.max(high.x, rd.max.x);
high.y = Math.max(high.y, rd.max.y);
}
genMin.setTo(low);
genMax.setTo(high);
}
public boolean isIn(Coord pos) public boolean isIn(Coord pos)
{ {
return pos.x >= 0 && pos.x < width && pos.y >= 0 && pos.y < height; return pos.x >= 0 && pos.x < width && pos.y >= 0 && pos.y < height;
@ -258,7 +295,7 @@ public class ScratchMap {
public boolean isClear(Coord min, Coord max) public boolean isClear(Coord min, Coord max)
{ {
if (!isIn(min) || !isIn(max)) return false; if (!isIn(min) || !isIn(max)) return false;
for (final RoomDesc r : rooms) { for (final RoomEntry r : rooms) {
if (r.intersectsWith(min, max)) return false; if (r.intersectsWith(min, max)) return false;
} }
@ -266,6 +303,12 @@ public class ScratchMap {
} }
public void protect(Coord pos, TileProtectLevel prot)
{
protect(pos, pos, prot);
}
public void protect(Coord min, Coord max, TileProtectLevel prot) public void protect(Coord min, Coord max, TileProtectLevel prot)
{ {
if (!isIn(min) || !isIn(max)) throw new WorldGenError("Tile(s) not in map: " + min + " , " + max); if (!isIn(min) || !isIn(max)) throw new WorldGenError("Tile(s) not in map: " + min + " , " + max);
@ -327,7 +370,7 @@ public class ScratchMap {
} }
} }
starts.add(start); starts.add(start);
start = Calc.pick(nodes); start = Calc.pick(rand, nodes);
} }
} }
@ -377,31 +420,24 @@ public class ScratchMap {
} }
/**
* @return dimensions of the area taken by non-null tiles
*/
public Coord getNeededSize() public Coord getNeededSize()
{ {
return Coord.make(genMax.x - genMin.x + 1, genMax.y - genMin.y + 1); return Coord.make(genMax.x - genMin.x + 1, genMax.y - genMin.y + 1);
} }
public int countBits(byte b)
{
int c = 0;
for (int i = 0; i < 8; i++) {
c += (b >> i) & 1;
}
return c;
}
public byte findWalls(Coord pos) public byte findWalls(Coord pos)
{ {
byte walls = 0; byte walls = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
final Coord cc = pos.add(Sides.get(i)); final Coord cc = pos.add(Moves.getSide(i));
if (!isIn(cc)) continue; if (!isIn(cc)) continue;
if (getTile(cc).isWall()) { if (getTile(cc).isWall()) {
walls |= Sides.bit(i); walls |= Moves.getBit(i);
} }
} }
return walls; return walls;
@ -412,11 +448,11 @@ public class ScratchMap {
{ {
byte floors = 0; byte floors = 0;
for (int i = 0; i <= 7; i++) { for (int i = 0; i <= 7; i++) {
final Coord cc = pos.add(Sides.get(i)); final Coord cc = pos.add(Moves.getSide(i));
if (!isIn(cc)) continue; if (!isIn(cc)) continue;
if (getTile(cc).isFloor()) { if (getTile(cc).isFloor()) {
floors |= Sides.bit(i); floors |= Moves.getBit(i);
} }
} }
return floors; return floors;
@ -427,11 +463,11 @@ public class ScratchMap {
{ {
byte doors = 0; byte doors = 0;
for (int i = 0; i <= 7; i++) { for (int i = 0; i <= 7; i++) {
final Coord cc = pos.add(Sides.get(i)); final Coord cc = pos.add(Moves.getSide(i));
if (!isIn(cc)) continue; if (!isIn(cc)) continue;
if (getTile(cc).isDoor()) { if (getTile(cc).isDoor()) {
doors |= Sides.bit(i); doors |= Moves.getBit(i);
} }
} }
return doors; return doors;
@ -442,105 +478,129 @@ public class ScratchMap {
{ {
byte nils = 0; byte nils = 0;
for (int i = 0; i <= 7; i++) { for (int i = 0; i <= 7; i++) {
final Coord cc = pos.add(Sides.get(i)); final Coord cc = pos.add(Moves.getSide(i));
if (!isIn(cc) || getTile(cc).isNull()) { if (!isIn(cc) || getTile(cc).isNull()) {
nils |= Sides.bit(i); nils |= Moves.getBit(i);
} }
} }
return nils; return nils;
} }
public void writeToLevel(Level level) /**
* Fix generator glitches and reduce size to the actual used size
*/
public void fixGlitches()
{ {
if (level.getWorld() == null) { final Tile[][] out = new Tile[height][width];
throw new WorldGenError("Level has no world assigned."); // need for entities
}
// make sure no walkable are at edges. // bounds will be adjusted by the actual tiles in the map
final Coord c = Coord.make(0, 0); genMin.x = width;
final Coord c1 = Coord.make(0, 0); genMin.y = height;
genMax.x = 0;
genMax.y = 0;
if (FIX_GLITCHES) { final Coord c = Coord.make(0, 0);
for (c.x = 0; c.x < width; c.x++) {
final Tile[][] out = new Tile[height][width]; for (c.y = 0; c.y < height; c.y++) {
for (c.x = 0; c.x < width; c.x++) { final Tile t = getTile(c);
for (c.y = 0; c.y < height; c.y++) { final boolean isNull = t.isNull();
final Tile t = getTile(c); final boolean isDoor = !isNull && t.isDoor();
final boolean isNull = t.isNull(); final boolean isFloor = !isNull && t.isFloor();
final boolean isWall = !isNull && t.isWall();
final boolean isDoor = !isNull && t.isDoor();
final boolean isFloor = !isNull && t.isFloor(); // bitmasks
final boolean isWall = !isNull && t.isWall(); final byte walls = findWalls(c);
final byte nils = findNils(c);
final byte floors = findFloors(c);
boolean toWall = false;
boolean toFloor = false;
boolean toNull = false;
do {
if (isWall && floors == 0) {
toNull = true;
break;
}
// bitmasks if (isFloor && (nils & Moves.BITS_CARDINAL) != 0) {
final byte walls = findWalls(c); toWall = true; // floor with adjacent cardinal null
final byte nils = findNils(c); break;
final byte floors = findFloors(c); }
boolean toWall = false; if (isNull && (floors & Moves.BITS_DIAGONAL) != 0) {
boolean toFloor = false; toWall = true; // null with adjacent diagonal floor
boolean toNull = false; break;
}
do { if (isDoor) {
if (isWall && floors == 0) {
toNull = true; if (Calc.countBits((byte) (floors & Moves.BITS_CARDINAL)) < 2) {
toWall = true;
break; break;
} }
if (isFloor && (nils & Sides.MASK_CARDINAL) != 0) { if (Calc.countBits((byte) (walls & Moves.BITS_CARDINAL)) > 2) {
toWall = true; // floor with adjacent cardinal null toWall = true;
break; break;
} }
if (isNull && (floors & Sides.MASK_DIAGONAL) != 0) { if (Calc.countBits((byte) (floors & Moves.BITS_CARDINAL)) > 2) {
toWall = true; // null with adjacent diagonal floor toFloor = true;
break; break;
} }
if (isDoor) { if ((floors & Moves.BITS_NW_CORNER) == Moves.BITS_NW_CORNER) toWall = true;
if ((floors & Moves.BITS_NE_CORNER) == Moves.BITS_NE_CORNER) toWall = true;
if (countBits((byte) (floors & Sides.MASK_CARDINAL)) < 2) { if ((floors & Moves.BITS_SW_CORNER) == Moves.BITS_SW_CORNER) toWall = true;
toWall = true; if ((floors & Moves.BITS_SE_CORNER) == Moves.BITS_SE_CORNER) toWall = true;
break;
}
if (countBits((byte) (walls & Sides.MASK_CARDINAL)) > 2) {
toWall = true;
break;
}
if (countBits((byte) (floors & Sides.MASK_CARDINAL)) > 2) {
toFloor = true;
break;
}
if ((floors & Sides.NW_CORNER) == Sides.NW_CORNER) toWall = true;
if ((floors & Sides.NE_CORNER) == Sides.NE_CORNER) toWall = true;
if ((floors & Sides.SW_CORNER) == Sides.SW_CORNER) toWall = true;
if ((floors & Sides.SE_CORNER) == Sides.SE_CORNER) toWall = true;
}
} while (false);
if (toNull) {
out[c.y][c.x] = Tiles.NULL.createTile();
} else if (toWall) {
out[c.y][c.x] = theme.wall().createTile();
} else if (toFloor) {
out[c.y][c.x] = theme.floor().createTile();
} else {
out[c.y][c.x] = map[c.y][c.x];
} }
} while (false);
if (toNull) {
out[c.y][c.x] = Tiles.NULL.createTile();
} else if (toWall) {
out[c.y][c.x] = theme.wall().createTile();
} else if (toFloor) {
out[c.y][c.x] = theme.floor().createTile();
} else {
out[c.y][c.x] = map[c.y][c.x];
}
if (!out[c.y][c.x].isNull()) {
genMin.x = Math.min(genMin.x, c.x);
genMin.y = Math.min(genMin.y, c.y);
genMax.x = Math.max(genMax.x, c.x);
genMax.y = Math.max(genMax.y, c.y);
} }
} }
map = out;
} }
map = out;
}
/**
* Write tiles and entities into a level
*
* @param level the level
*/
public void writeToLevel(Level level)
{
if (level.getWorld() == null) {
throw new WorldGenError("Level has no world assigned."); // need for entities
}
// make sure no walkable are at edges.
final Coord c = Coord.make(0, 0);
final Coord c1 = Coord.make(0, 0);
for (c.x = genMin.x, c1.x = 0; c.x <= genMax.x; c.x++, c1.x++) { for (c.x = genMin.x, c1.x = 0; c.x <= genMax.x; c.x++, c1.x++) {
for (c.y = genMin.y, c1.y = 0; c.y <= genMax.y; c.y++, c1.y++) { for (c.y = genMin.y, c1.y = 0; c.y <= genMax.y; c.y++, c1.y++) {
level.setTile(c1, getTile(c)); level.setTile(c1, getTile(c));
@ -582,60 +642,74 @@ public class ScratchMap {
} }
public boolean putItem(Item item, Coord pos) public boolean addItem(Item item, Coord pos)
{
return addItem(item, pos, true);
}
public boolean addItem(Item item, Coord pos, boolean canStack)
{ {
if (!isIn(pos)) return false; if (!isIn(pos)) return false;
final Tile t = getTile(pos); final Tile t = getTile(pos);
if (!canStack && t.hasItem()) return false;
if (t.dropItem(item)) return true; if (t.dropItem(item)) return true;
return false; return false;
} }
public boolean putItemInArea(Item item, Coord min, Coord max, int tries) public boolean addItemInArea(Item item, Coord min, Coord max, int tries)
{ {
final Coord pos = Coord.zero(); final Coord pos = Coord.zero();
for (int i = 0; i < tries; i++) { for (int i = 0; i < tries / 2; i++) {
pos.x = min.x + rand.nextInt(max.x - min.x); pos.x = Calc.randInt(rand, min.x, max.x);
pos.y = min.y + rand.nextInt(max.y - min.y); pos.y = Calc.randInt(rand, min.y, max.y);
if (putItem(item, pos)) return true; if (addItem(item, pos, false)) return true;
}
for (int i = 0; i < tries - (tries / 2); i++) {
pos.x = Calc.randInt(rand, min.x, max.x);
pos.y = Calc.randInt(rand, min.y, max.y);
if (addItem(item, pos, true)) return true;
} }
return false; return false;
} }
public boolean putItemInMap(Item item, int tries) public boolean addItemInMap(Item item, int tries)
{ {
return putItemInArea(item, genMin, genMax, tries); Log.f3("gen bounds: " + genMin + " -> " + genMax);
return addItemInArea(item, genMin, genMax, tries);
} }
public boolean putEntityInArea(Entity entity, Coord min, Coord max, int tries) public boolean addEntityInArea(Entity entity, Coord min, Coord max, int tries)
{ {
final Coord pos = Coord.zero(); final Coord pos = Coord.zero();
for (int i = 0; i < tries; i++) { for (int i = 0; i < tries; i++) {
pos.x = min.x + rand.nextInt(max.x - min.x); pos.x = Calc.randInt(rand, min.x, max.x);
pos.y = min.y + rand.nextInt(max.y - min.y); pos.y = Calc.randInt(rand, min.y, max.y);
if (!isIn(pos)) continue; if (!isIn(pos)) continue;
if (putEntity(entity, pos)) return true; if (addEntity(entity, pos)) return true;
} }
return false; return false;
} }
public boolean putEntityInMap(Entity entity, int tries) public boolean addEntityInMap(Entity entity, int tries)
{ {
return putEntityInArea(entity, genMin, genMax, tries); return addEntityInArea(entity, genMin, genMax, tries);
} }
public boolean putEntity(Entity entity, Coord pos) public boolean addEntity(Entity entity, Coord pos)
{ {
if (!isIn(pos)) return false; if (!isIn(pos)) return false;

@ -1,9 +1,21 @@
package mightypork.rogue.world.gen; package mightypork.rogue.world.gen;
import java.util.ArrayList;
import java.util.List;
import java.util.Random; import java.util.Random;
import mightypork.gamecore.logging.Log;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.Range;
import mightypork.rogue.world.World; import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.gen.LevelBuilder.BuildOrder;
import mightypork.rogue.world.gen.themes.ThemeBrick;
import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.Items;
public class WorldCreator { public class WorldCreator {
@ -15,20 +27,127 @@ public class WorldCreator {
{ {
synchronized (rand) { synchronized (rand) {
rand.setSeed(seed); rand.setSeed(seed);
final MapTheme theme = new ThemeBrick();
final World w = new World(); final World w = new World();
w.setSeed(seed); w.setSeed(seed);
final int count = 7; final LevelBuilder levelBuilders[] = new LevelBuilder[7];
for (int lvl = 1; lvl <= count; lvl++) { // build the level rooms
w.addLevel(LevelGenerator.build(w, rand.nextLong(), lvl, LevelGenerator.DUNGEON_THEME, lvl == count)); for (int floor = 1; floor <= 7; floor++) {
final LevelBuilder lb = prepareFloor(rand.nextLong(), floor, theme, floor == 7);
levelBuilders[floor - 1] = lb;
} }
final List<ItemModel> weaponsBasic = new ArrayList<>();
weaponsBasic.add(Items.ROCK);
weaponsBasic.add(Items.BONE);
weaponsBasic.add(Items.TWIG);
final List<ItemModel> weaponsMedium = new ArrayList<>();
weaponsMedium.add(Items.CLUB);
final List<ItemModel> weaponsGood = new ArrayList<>();
weaponsGood.add(Items.AXE);
weaponsGood.add(Items.SWORD);
weaponsBasic.add(Items.KNIFE);
for (int i = 0; i < Calc.randInt(rand, 10, 15); i++) {
final Item item = Calc.pick(rand, weaponsBasic).createItemDamaged(50);
final LevelBuilder lb = levelBuilders[-1 + Calc.randInt(1, 7)];
lb.addItem(item, false);
}
for (int i = 0; i < Calc.randInt(rand, 1, 3); i++) {
final Item item = Calc.pick(rand, weaponsMedium).createItemDamaged(60);
final LevelBuilder lb = levelBuilders[-1 + Calc.randInt(1, 3)];
lb.addItem(item, false);
}
for (int i = 0; i < Calc.randInt(rand, 2, 3); i++) {
final Item item = Calc.pick(rand, weaponsGood).createItemDamaged(60);
final LevelBuilder lb = levelBuilders[-1 + Calc.randInt(3, 7)];
lb.addRoom(Rooms.treasure(item), BuildOrder.MIDDLE, true);
}
// place random foods
final List<ItemModel> randomFood = new ArrayList<>();
randomFood.add(Items.CHEESE);
randomFood.add(Items.MEAT);
for (int level = 1; level <= 7; level++) {
final LevelBuilder lb = levelBuilders[level - 1];
final Range amount = Range.make(1, level);
for (int i = 0; i < amount.randInt(rand); i++) {
lb.addItem(Calc.pick(rand, randomFood).createItem(), false);
}
}
// place monsters
for (int level = 1; level <= 7; level++) {
final LevelBuilder lb = levelBuilders[level - 1];
final Range amount = Range.make(2 + level * 2, 5 + level * 3.5);
for (int i = 0; i < amount.randInt(rand); i++) {
Entity e;
if (level > 2 && rand.nextInt(7 - level + 1) == 0) {
e = Entities.RAT_BROWN.createEntity();
} else {
e = Entities.RAT_GRAY.createEntity();
}
lb.addEntity(e, false);
}
}
// compile levels
for (final LevelBuilder lb : levelBuilders) {
w.addLevel(lb.build(w));
}
w.createPlayer(); w.createPlayer();
return w; return w;
} }
} }
public static LevelBuilder prepareFloor(long seed, int floor, MapTheme theme, boolean lastLevel) throws WorldGenError
{
Log.f3("Generating level: " + floor);
final LevelBuilder lb = new LevelBuilder(128, theme, seed);
lb.addRoom(Rooms.ENTRANCE, BuildOrder.FIRST, true);
lb.addRoom(Rooms.BASIC, Range.make(1 + floor, 1 + floor * 1.5), BuildOrder.MIDDLE, false);
lb.addRoom(Rooms.DEAD_END, Range.make(0, 1 + floor * 0.6), BuildOrder.MIDDLE, false);
lb.addRoom(Rooms.STORAGE, Range.make(1, Math.ceil(floor / 2D)), BuildOrder.MIDDLE, false);
if (lastLevel) lb.addRoom(Rooms.BOSS, BuildOrder.LAST, true);
if (!lastLevel) lb.addRoom(Rooms.EXIT, BuildOrder.LAST, true);
final RoomBuilder heartRoom = Rooms.shrine(Items.HEART_PIECE.createItem());
lb.addRoom(heartRoom, BuildOrder.LAST, true);
return lb;
}
} }

@ -5,10 +5,10 @@ import java.util.Random;
import mightypork.gamecore.util.annot.DefaultImpl; import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.algo.Moves;
import mightypork.rogue.world.gen.MapTheme; import mightypork.rogue.world.gen.MapTheme;
import mightypork.rogue.world.gen.RoomBuilder; import mightypork.rogue.world.gen.RoomBuilder;
import mightypork.rogue.world.gen.RoomDesc; import mightypork.rogue.world.gen.RoomEntry;
import mightypork.rogue.world.gen.ScratchMap; import mightypork.rogue.world.gen.ScratchMap;
import mightypork.rogue.world.gen.TileProtectLevel; import mightypork.rogue.world.gen.TileProtectLevel;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
@ -17,7 +17,7 @@ import mightypork.rogue.world.tile.TileModel;
public abstract class AbstractRectRoom implements RoomBuilder { public abstract class AbstractRectRoom implements RoomBuilder {
@Override @Override
public RoomDesc buildToFit(ScratchMap map, MapTheme theme, Random rand, Coord center) public RoomEntry buildRoom(ScratchMap map, MapTheme theme, Random rand, Coord center)
{ {
// half width, half height actually // half width, half height actually
final Coord innerSize = getInnerSize(rand); final Coord innerSize = getInnerSize(rand);
@ -42,7 +42,7 @@ public abstract class AbstractRectRoom implements RoomBuilder {
buildExtras(map, theme, rand, min, max); buildExtras(map, theme, rand, min, max);
return new RoomDesc(min.add(-1, -1), max); return new RoomEntry(min.add(-1, -1), max);
} }
@ -84,7 +84,7 @@ public abstract class AbstractRectRoom implements RoomBuilder {
break; break;
} }
if ((map.findDoors(door) & Sides.MASK_CARDINAL) == 0) { if ((map.findDoors(door) & Moves.BITS_CARDINAL) == 0) {
map.set(door, getDoorType(theme, rand)); map.set(door, getDoorType(theme, rand));
i++; // increment pointer i++; // increment pointer
} }

@ -3,7 +3,6 @@ package mightypork.rogue.world.gen.rooms;
import java.util.Random; import java.util.Random;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.entity.Entities; import mightypork.rogue.world.entity.Entities;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
@ -17,21 +16,42 @@ public class BossRoom extends SecretRoom {
@Override @Override
protected int getDoorCount(Random rand) protected int getDoorCount(Random rand)
{ {
return Calc.randInt(rand, 1, 3); return 1;
} }
@Override @Override
protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max) protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max)
{ {
final Coord bossPos = min.add(3, 3);
final Entity boss = Entities.RAT_BOSS.createEntity(); final Entity boss = Entities.RAT_BOSS.createEntity();
if (!map.putEntityInArea(boss, min, max, 100)) { if (!map.addEntity(boss, bossPos)) {
throw new WorldGenError("Could not place boss.");
// just place it anywhere then
if (!map.putEntityInMap(boss, 100)) {
throw new WorldGenError("Could not place boss.");
}
} }
Entity rat;
// 4 guardian rats
rat = Entities.RAT_BROWN.createEntity();
map.addEntity(rat, min.add(1, 1));
rat = Entities.RAT_BROWN.createEntity();
map.addEntity(rat, Coord.make(max.x - 1, min.y + 1));
rat = Entities.RAT_BROWN.createEntity();
map.addEntity(rat, max.add(-1, -1));
rat = Entities.RAT_BROWN.createEntity();
map.addEntity(rat, Coord.make(min.x + 1, max.y - 1));
}
@Override
protected Coord getInnerSize(Random rand)
{
return Coord.make(5, 5);
} }
} }

@ -6,14 +6,14 @@ import java.util.Random;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.gen.MapTheme; import mightypork.rogue.world.gen.MapTheme;
import mightypork.rogue.world.gen.RoomBuilder; import mightypork.rogue.world.gen.RoomBuilder;
import mightypork.rogue.world.gen.RoomDesc; import mightypork.rogue.world.gen.RoomEntry;
import mightypork.rogue.world.gen.ScratchMap; import mightypork.rogue.world.gen.ScratchMap;
public class DeadEndRoom implements RoomBuilder { public class DeadEndRoom implements RoomBuilder {
@Override @Override
public RoomDesc buildToFit(ScratchMap map, MapTheme theme, Random rand, Coord center) public RoomEntry buildRoom(ScratchMap map, MapTheme theme, Random rand, Coord center)
{ {
final Coord low = center.add(-1, -1); final Coord low = center.add(-1, -1);
final Coord high = center; final Coord high = center;
@ -21,6 +21,6 @@ public class DeadEndRoom implements RoomBuilder {
map.set(center, theme.floor()); map.set(center, theme.floor());
return new RoomDesc(low, high); return new RoomEntry(low, high);
} }
} }

@ -9,30 +9,33 @@ import mightypork.rogue.world.gen.MapTheme;
import mightypork.rogue.world.gen.ScratchMap; import mightypork.rogue.world.gen.ScratchMap;
import mightypork.rogue.world.gen.WorldGenError; import mightypork.rogue.world.gen.WorldGenError;
import mightypork.rogue.world.item.Item; import mightypork.rogue.world.item.Item;
import mightypork.rogue.world.item.Items;
public class HeartPieceRoom extends SecretRoom { public class ItemShrineRoom extends SecretRoom {
private final Item item;
public ItemShrineRoom(Item item)
{
this.item = item;
}
@Override @Override
protected int getDoorCount(Random rand) protected int getDoorCount(Random rand)
{ {
return Calc.randInt(rand, 1, 3); return Calc.randInt(rand, 1, 4);
} }
@Override @Override
protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max) protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max)
{ {
final Item heart = Items.HEART_PIECE.createItem(); final Coord center = min.add(2, 2);
if (!map.putItem(heart, min.add(2, 2))) { if (!map.addItem(item, center)) {
if (!map.putItemInArea(heart, min, max, 100)) { throw new WorldGenError("Could not place item in chest.");
if (!map.putItemInMap(heart, 100)) {
throw new WorldGenError("Could not place heart piece.");
}
}
} }
} }

@ -1,16 +0,0 @@
package mightypork.rogue.world.gen.rooms;
import mightypork.rogue.world.gen.RoomBuilder;
public class Rooms {
public static final RoomBuilder BASIC = new BasicRoom();
public static final RoomBuilder TREASURE = new TreasureRoom();
public static final RoomBuilder DEAD_END = new DeadEndRoom();
public static final RoomBuilder ENTRANCE = new EntranceRoom();
public static final RoomBuilder EXIT = new ExitRoom();
public static final RoomBuilder BOSS = new BossRoom();
public static final RoomBuilder HEART_ROOM = new HeartPieceRoom();
}

@ -0,0 +1,50 @@
package mightypork.rogue.world.gen.rooms;
import java.util.Random;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.gen.MapTheme;
import mightypork.rogue.world.gen.ScratchMap;
import mightypork.rogue.world.item.Items;
public class StorageRoom extends SecretRoom {
@Override
protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max)
{
int maxStuff = 3;
for (int i = 0; i < Calc.randInt(rand, 0, 1); i++) {
map.addItemInArea(Items.SANDWICH.createItem(), min, max, 50);
if (--maxStuff == 0) break;
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.addItemInArea(Items.TWIG.createItemDamaged(40), min, max, 50);
if (--maxStuff == 0) break;
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.addItemInArea(Items.BONE.createItemDamaged(40), min, max, 50);
if (--maxStuff == 0) break;
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.addItemInArea(Items.MEAT.createItem(), min, max, 50);
if (--maxStuff == 0) break;
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.addItemInArea(Items.CHEESE.createItem(), min, max, 50);
if (--maxStuff == 0) break;
}
for (int i = 0; i < Calc.randInt(rand, 0, 1); i++) {
map.addItemInArea(Items.ROCK.createItemDamaged(30), min, max, 50);
if (--maxStuff == 0) break;
}
}
}

@ -0,0 +1,33 @@
package mightypork.rogue.world.gen.rooms;
import java.util.Random;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.gen.MapTheme;
import mightypork.rogue.world.gen.ScratchMap;
import mightypork.rogue.world.gen.TileProtectLevel;
import mightypork.rogue.world.item.Item;
public class TreasureChestRoom extends ItemShrineRoom {
public TreasureChestRoom(Item item)
{
super(item);
}
@Override
protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max)
{
// set tile
final Coord center = min.add(2, 2);
map.set(center, theme.chest());
map.protect(center, TileProtectLevel.STRONG);
// drop item
super.buildExtras(map, theme, rand, min, max);
}
}

@ -1,38 +0,0 @@
package mightypork.rogue.world.gen.rooms;
import java.util.Random;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.Coord;
import mightypork.rogue.world.gen.MapTheme;
import mightypork.rogue.world.gen.ScratchMap;
import mightypork.rogue.world.item.Items;
public class TreasureRoom extends SecretRoom {
@Override
protected void buildExtras(ScratchMap map, MapTheme theme, Random rand, Coord min, Coord max)
{
for (int i = 0; i < Calc.randInt(rand, 0, 1); i++) {
map.putItemInArea(Items.SANDWICH.createItem(), min, max, 50);
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.putItemInArea(Items.BONE.createItemDamaged(20), min, max, 50);
}
for (int i = 0; i < Calc.randInt(rand, 0, 1); i++) {
map.putItemInArea(Items.ROCK.createItemDamaged(30), min, max, 50);
}
for (int i = 0; i < Calc.randInt(rand, 0, 3); i++) {
map.putItemInArea(Items.MEAT.createItem(), min, max, 50);
}
for (int i = 0; i < Calc.randInt(rand, 0, 2); i++) {
map.putItemInArea(Items.CHEESE.createItem(), min, max, 50);
}
}
}

@ -56,4 +56,11 @@ public class ThemeBrick implements MapTheme {
{ {
return Tiles.BRICK_EXIT; return Tiles.BRICK_EXIT;
} }
@Override
public TileModel chest()
{
return Tiles.BRICK_CHEST;
}
} }

@ -6,8 +6,8 @@ import mightypork.gamecore.input.InputSystem;
import mightypork.gamecore.input.Keys; import mightypork.gamecore.input.Keys;
import mightypork.gamecore.input.events.KeyEvent; import mightypork.gamecore.input.events.KeyEvent;
import mightypork.gamecore.input.events.KeyListener; import mightypork.gamecore.input.events.KeyListener;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Moves;
import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.rogue.world.entity.impl.PlayerEntity; import mightypork.rogue.world.entity.impl.PlayerEntity;
import mightypork.rogue.world.events.PlayerStepEndListener; import mightypork.rogue.world.events.PlayerStepEndListener;
@ -17,7 +17,7 @@ import mightypork.rogue.world.gui.MapView;
public class MIPKeyboard extends MapInteractionPlugin implements PlayerStepEndListener, KeyListener, Updateable { public class MIPKeyboard extends MapInteractionPlugin implements PlayerStepEndListener, KeyListener, Updateable {
private static final int[] keys = { Keys.LEFT, Keys.RIGHT, Keys.UP, Keys.DOWN }; private static final int[] keys = { Keys.LEFT, Keys.RIGHT, Keys.UP, Keys.DOWN };
private static final Step[] sides = { Sides.W, Sides.E, Sides.N, Sides.S }; private static final Move[] sides = { Moves.W, Moves.E, Moves.N, Moves.S };
public MIPKeyboard(MapView mapView) public MIPKeyboard(MapView mapView)
@ -72,7 +72,7 @@ public class MIPKeyboard extends MapInteractionPlugin implements PlayerStepEndLi
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (InputSystem.isKeyDown(keys[i])) { if (InputSystem.isKeyDown(keys[i])) {
final Step side = sides[i]; final Move side = sides[i];
if (mapView.plc.canGo(side)) { if (mapView.plc.canGo(side)) {
mapView.plc.go(side); mapView.plc.go(side);
return true; return true;

@ -6,7 +6,7 @@ import mightypork.gamecore.input.InputSystem;
import mightypork.gamecore.util.math.Calc.Deg; import mightypork.gamecore.util.math.Calc.Deg;
import mightypork.gamecore.util.math.Polar; import mightypork.gamecore.util.math.Polar;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.algo.Moves;
import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.rogue.world.entity.impl.PlayerEntity; import mightypork.rogue.world.entity.impl.PlayerEntity;
import mightypork.rogue.world.events.PlayerStepEndListener; import mightypork.rogue.world.events.PlayerStepEndListener;
@ -97,16 +97,16 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
switch (dir) { switch (dir) {
case 0: case 0:
return mapView.plc.tryGo(Sides.E); return mapView.plc.tryGo(Moves.E);
case 1: case 1:
return mapView.plc.tryGo(Sides.S); return mapView.plc.tryGo(Moves.S);
case 2: case 2:
return mapView.plc.tryGo(Sides.W); return mapView.plc.tryGo(Moves.W);
case 3: case 3:
return mapView.plc.tryGo(Sides.N); return mapView.plc.tryGo(Moves.N);
} }
return false; return false;

@ -10,11 +10,7 @@ import mightypork.rogue.world.item.impl.active.ItemHeartPiece;
import mightypork.rogue.world.item.impl.food.ItemCheese; import mightypork.rogue.world.item.impl.food.ItemCheese;
import mightypork.rogue.world.item.impl.food.ItemMeat; import mightypork.rogue.world.item.impl.food.ItemMeat;
import mightypork.rogue.world.item.impl.food.ItemSandwich; import mightypork.rogue.world.item.impl.food.ItemSandwich;
import mightypork.rogue.world.item.impl.weapons.ItemBone; import mightypork.rogue.world.item.impl.weapons.*;
import mightypork.rogue.world.item.impl.weapons.ItemClub;
import mightypork.rogue.world.item.impl.weapons.ItemHammer;
import mightypork.rogue.world.item.impl.weapons.ItemStone;
import mightypork.rogue.world.item.impl.weapons.ItemSword;
/** /**
@ -31,10 +27,12 @@ public final class Items {
public static final ItemModel BONE = new ItemModel(3, ItemBone.class); public static final ItemModel BONE = new ItemModel(3, ItemBone.class);
public static final ItemModel SANDWICH = new ItemModel(4, ItemSandwich.class); public static final ItemModel SANDWICH = new ItemModel(4, ItemSandwich.class);
public static final ItemModel CLUB = new ItemModel(5, ItemClub.class); public static final ItemModel CLUB = new ItemModel(5, ItemClub.class);
public static final ItemModel HAMMER = new ItemModel(6, ItemHammer.class); public static final ItemModel AXE = new ItemModel(6, ItemAxe.class);
public static final ItemModel SWORD = new ItemModel(7, ItemSword.class); public static final ItemModel SWORD = new ItemModel(7, ItemSword.class);
public static final ItemModel ROCK = new ItemModel(8, ItemStone.class); public static final ItemModel ROCK = new ItemModel(8, ItemRock.class);
public static final ItemModel HEART_PIECE = new ItemModel(9, ItemHeartPiece.class); public static final ItemModel HEART_PIECE = new ItemModel(9, ItemHeartPiece.class);
public static final ItemModel TWIG = new ItemModel(10, ItemTwig.class);
public static final ItemModel KNIFE = new ItemModel(11, ItemKnife.class);
public static void register(int id, ItemModel model) public static void register(int id, ItemModel model)

@ -21,7 +21,7 @@ public class ItemHeartPiece extends Item {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.heart_piece")); return new QuadItemRenderer(this, Res.getTxQuad("item.heart_piece"));
} }

@ -19,7 +19,7 @@ public class ItemCheese extends ItemBaseFood {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.cheese")); return new QuadItemRenderer(this, Res.getTxQuad("item.cheese"));
} }

@ -19,7 +19,7 @@ public class ItemMeat extends ItemBaseFood {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.meat")); return new QuadItemRenderer(this, Res.getTxQuad("item.meat"));
} }

@ -19,7 +19,7 @@ public class ItemSandwich extends ItemBaseFood {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.sandwich")); return new QuadItemRenderer(this, Res.getTxQuad("item.sandwich"));
} }

@ -8,9 +8,9 @@ import mightypork.rogue.world.item.impl.ItemBaseWeapon;
import mightypork.rogue.world.item.render.QuadItemRenderer; import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemHammer extends ItemBaseWeapon { public class ItemAxe extends ItemBaseWeapon {
public ItemHammer(ItemModel model) public ItemAxe(ItemModel model)
{ {
super(model); super(model);
} }
@ -19,7 +19,7 @@ public class ItemHammer extends ItemBaseWeapon {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.hammer")); return new QuadItemRenderer(this, Res.getTxQuad("item.axe"));
} }
@ -33,13 +33,13 @@ public class ItemHammer extends ItemBaseWeapon {
@Override @Override
public int getMaxUses() public int getMaxUses()
{ {
return 100; return 70;
} }
@Override @Override
public String getVisualName() public String getVisualName()
{ {
return "Hammer"; return "Axe";
} }
} }

@ -19,7 +19,7 @@ public class ItemBone extends ItemBaseWeapon {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.bone")); return new QuadItemRenderer(this, Res.getTxQuad("item.bone"));
} }

@ -19,7 +19,7 @@ public class ItemClub extends ItemBaseWeapon {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.club")); return new QuadItemRenderer(this, Res.getTxQuad("item.club"));
} }

@ -0,0 +1,45 @@
package mightypork.rogue.world.item.impl.weapons;
import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer;
import mightypork.rogue.world.item.impl.ItemBaseWeapon;
import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemKnife extends ItemBaseWeapon {
public ItemKnife(ItemModel model)
{
super(model);
}
@Override
protected ItemRenderer makeRenderer()
{
return new QuadItemRenderer(this, Res.getTxQuad("item.knife"));
}
@Override
public int getAttackPoints()
{
return 4;
}
@Override
public int getMaxUses()
{
return 60;
}
@Override
public String getVisualName()
{
return "Knife";
}
}

@ -8,9 +8,9 @@ import mightypork.rogue.world.item.impl.ItemBaseWeapon;
import mightypork.rogue.world.item.render.QuadItemRenderer; import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemStone extends ItemBaseWeapon { public class ItemRock extends ItemBaseWeapon {
public ItemStone(ItemModel model) public ItemRock(ItemModel model)
{ {
super(model); super(model);
} }
@ -19,7 +19,7 @@ public class ItemStone extends ItemBaseWeapon {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.stone")); return new QuadItemRenderer(this, Res.getTxQuad("item.stone"));
} }

@ -19,14 +19,14 @@ public class ItemSword extends ItemBaseWeapon {
@Override @Override
protected ItemRenderer makeRenderer() protected ItemRenderer makeRenderer()
{ {
return new QuadItemRenderer(this, Res.txq("item.sword")); return new QuadItemRenderer(this, Res.getTxQuad("item.sword"));
} }
@Override @Override
public int getAttackPoints() public int getAttackPoints()
{ {
return 6; return 5;
} }

@ -0,0 +1,45 @@
package mightypork.rogue.world.item.impl.weapons;
import mightypork.rogue.Res;
import mightypork.rogue.world.item.ItemModel;
import mightypork.rogue.world.item.ItemRenderer;
import mightypork.rogue.world.item.impl.ItemBaseWeapon;
import mightypork.rogue.world.item.render.QuadItemRenderer;
public class ItemTwig extends ItemBaseWeapon {
public ItemTwig(ItemModel model)
{
super(model);
}
@Override
protected ItemRenderer makeRenderer()
{
return new QuadItemRenderer(this, Res.getTxQuad("item.twig"));
}
@Override
public int getAttackPoints()
{
return 1;
}
@Override
public int getMaxUses()
{
return 10;
}
@Override
public String getVisualName()
{
return "Twig";
}
}

@ -16,8 +16,8 @@ import mightypork.gamecore.util.ion.IonObjBinary;
import mightypork.gamecore.util.ion.IonOutput; import mightypork.gamecore.util.ion.IonOutput;
import mightypork.gamecore.util.math.Calc; import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Moves;
import mightypork.gamecore.util.math.algo.floodfill.FloodFill; import mightypork.gamecore.util.math.algo.floodfill.FloodFill;
import mightypork.gamecore.util.math.constraints.vect.Vect; import mightypork.gamecore.util.math.constraints.vect.Vect;
import mightypork.gamecore.util.math.noise.NoiseGen; import mightypork.gamecore.util.math.noise.NoiseGen;
@ -63,9 +63,9 @@ public class Level implements BusAccess, Updateable, DelegatingClient, Toggleabl
private final FloodFill exploreFiller = new FloodFill() { private final FloodFill exploreFiller = new FloodFill() {
@Override @Override
public Step[] getSpreadSides() public List<Move> getSpreadSides()
{ {
return Sides.ALL_SIDES; return Moves.ALL_SIDES;
} }

@ -2,7 +2,7 @@ package mightypork.rogue.world.level.render;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.algo.Step; import mightypork.gamecore.util.math.algo.Move;
import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound; import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound;
import mightypork.gamecore.util.math.noise.NoiseGen; import mightypork.gamecore.util.math.noise.NoiseGen;
@ -46,7 +46,7 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
* @param offset offsets * @param offset offsets
* @return the tile at that position * @return the tile at that position
*/ */
public Tile getAdjacentTile(Step offset) public Tile getAdjacentTile(Move offset)
{ {
return map.getTile(pos.add(offset)); return map.getTile(pos.add(offset));
} }

@ -98,6 +98,8 @@ public abstract class Tile implements BusAccess, IonObjBlob {
@DefaultImpl @DefaultImpl
public void renderExtra(TileRenderContext context) public void renderExtra(TileRenderContext context)
{ {
initRenderer();
renderer.renderExtra(context);
} }

@ -0,0 +1,22 @@
package mightypork.rogue.world.tile;
import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.color.pal.RGB;
public class TileColors {
public static final Color NULL = RGB.NONE;
public static final Color FLOOR = RGB.GRAY_DARK;
public static final Color WALL = RGB.GRAY_LIGHT;
public static final Color DOOR = RGB.BROWN;
public static final Color COLLAPSED_WALL = RGB.GRAY;
public static final Color ENTRANCE = RGB.CYAN;
public static final Color EXIT = Color.fromHex(0x00EA8C);
public static final Color SECRET_DOOR_REVEALED = RGB.PINK;
public static final Color SECRET_DOOR_HIDDEN = WALL;
}

@ -4,7 +4,8 @@ package mightypork.rogue.world.tile;
import mightypork.gamecore.eventbus.events.Updateable; import mightypork.gamecore.eventbus.events.Updateable;
import mightypork.gamecore.render.Render; import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad; import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.gamecore.util.math.algo.Sides; import mightypork.gamecore.util.annot.DefaultImpl;
import mightypork.gamecore.util.math.algo.Moves;
import mightypork.gamecore.util.math.constraints.rect.Rect; import mightypork.gamecore.util.math.constraints.rect.Rect;
import mightypork.rogue.Res; import mightypork.rogue.Res;
import mightypork.rogue.world.level.render.TileRenderContext; import mightypork.rogue.world.level.render.TileRenderContext;
@ -44,24 +45,24 @@ public abstract class TileRenderer implements Updateable {
this.tile = tile; this.tile = tile;
if (!inited) { if (!inited) {
SH_N = Res.txq("tile.shadow.n"); SH_N = Res.getTxQuad("tile.shadow.n");
SH_S = Res.txq("tile.shadow.s"); SH_S = Res.getTxQuad("tile.shadow.s");
SH_E = Res.txq("tile.shadow.e"); SH_E = Res.getTxQuad("tile.shadow.e");
SH_W = Res.txq("tile.shadow.w"); SH_W = Res.getTxQuad("tile.shadow.w");
SH_NW = Res.txq("tile.shadow.nw"); SH_NW = Res.getTxQuad("tile.shadow.nw");
SH_NE = Res.txq("tile.shadow.ne"); SH_NE = Res.getTxQuad("tile.shadow.ne");
SH_SW = Res.txq("tile.shadow.sw"); SH_SW = Res.getTxQuad("tile.shadow.sw");
SH_SE = Res.txq("tile.shadow.se"); SH_SE = Res.getTxQuad("tile.shadow.se");
UFOG_N = Res.txq("tile.ufog.n"); UFOG_N = Res.getTxQuad("tile.ufog.n");
UFOG_S = Res.txq("tile.ufog.s"); UFOG_S = Res.getTxQuad("tile.ufog.s");
UFOG_E = Res.txq("tile.ufog.e"); UFOG_E = Res.getTxQuad("tile.ufog.e");
UFOG_W = Res.txq("tile.ufog.w"); UFOG_W = Res.getTxQuad("tile.ufog.w");
UFOG_NW = Res.txq("tile.ufog.nw"); UFOG_NW = Res.getTxQuad("tile.ufog.nw");
UFOG_NE = Res.txq("tile.ufog.ne"); UFOG_NE = Res.getTxQuad("tile.ufog.ne");
UFOG_SW = Res.txq("tile.ufog.sw"); UFOG_SW = Res.getTxQuad("tile.ufog.sw");
UFOG_SE = Res.txq("tile.ufog.se"); UFOG_SE = Res.getTxQuad("tile.ufog.se");
UFOG_FULL = Res.txq("tile.ufog.full"); UFOG_FULL = Res.getTxQuad("tile.ufog.full");
inited = true; inited = true;
} }
} }
@ -78,9 +79,9 @@ public abstract class TileRenderer implements Updateable {
shadows = 0; // reset the mask shadows = 0; // reset the mask
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
final Tile t2 = context.getAdjacentTile(Sides.get(i)); final Tile t2 = context.getAdjacentTile(Moves.getSide(i));
if (!t2.isNull() && t2.doesCastShadow()) { if (!t2.isNull() && t2.doesCastShadow()) {
shadows |= Sides.bit(i); shadows |= Moves.getBit(i);
} }
} }
@ -90,16 +91,22 @@ public abstract class TileRenderer implements Updateable {
if (shadows == 0) return; if (shadows == 0) return;
final Rect rect = context.getRect(); final Rect rect = context.getRect();
if ((shadows & Sides.NW_CORNER) == Sides.MASK_NW) Render.quadTextured(rect, SH_NW); if ((shadows & Moves.BITS_NW_CORNER) == Moves.BIT_NW) Render.quadTextured(rect, SH_NW);
if ((shadows & Sides.MASK_N) != 0) Render.quadTextured(rect, SH_N); if ((shadows & Moves.BIT_N) != 0) Render.quadTextured(rect, SH_N);
if ((shadows & Sides.NE_CORNER) == Sides.MASK_NE) Render.quadTextured(rect, SH_NE); if ((shadows & Moves.BITS_NE_CORNER) == Moves.BIT_NE) Render.quadTextured(rect, SH_NE);
if ((shadows & Sides.MASK_W) != 0) Render.quadTextured(rect, SH_W); if ((shadows & Moves.BIT_W) != 0) Render.quadTextured(rect, SH_W);
if ((shadows & Sides.MASK_E) != 0) Render.quadTextured(rect, SH_E); if ((shadows & Moves.BIT_E) != 0) Render.quadTextured(rect, SH_E);
if ((shadows & Sides.SW_CORNER) == Sides.MASK_SW) Render.quadTextured(rect, SH_SW); if ((shadows & Moves.BITS_SW_CORNER) == Moves.BIT_SW) Render.quadTextured(rect, SH_SW);
if ((shadows & Sides.MASK_S) != 0) Render.quadTextured(rect, SH_S); if ((shadows & Moves.BIT_S) != 0) Render.quadTextured(rect, SH_S);
if ((shadows & Sides.SE_CORNER) == Sides.MASK_SE) Render.quadTextured(rect, SH_SE); if ((shadows & Moves.BITS_SE_CORNER) == Moves.BIT_SE) Render.quadTextured(rect, SH_SE);
}
@DefaultImpl
public void renderExtra(TileRenderContext context)
{
} }
@ -117,24 +124,24 @@ public abstract class TileRenderer implements Updateable {
byte ufog = 0; byte ufog = 0;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
final Tile t2 = context.getAdjacentTile(Sides.get(i)); final Tile t2 = context.getAdjacentTile(Moves.getSide(i));
if (t2.isNull() || !t2.isExplored()) { if (t2.isNull() || !t2.isExplored()) {
ufog |= Sides.bit(i); ufog |= Moves.getBit(i);
} }
} }
if (ufog == 0) return; if (ufog == 0) return;
if ((ufog & Sides.NW_CORNER) == Sides.MASK_NW) Render.quadTextured(rect, UFOG_NW); if ((ufog & Moves.BITS_NW_CORNER) == Moves.BIT_NW) Render.quadTextured(rect, UFOG_NW);
if ((ufog & Sides.MASK_N) != 0) Render.quadTextured(rect, UFOG_N); if ((ufog & Moves.BIT_N) != 0) Render.quadTextured(rect, UFOG_N);
if ((ufog & Sides.NE_CORNER) == Sides.MASK_NE) Render.quadTextured(rect, UFOG_NE); if ((ufog & Moves.BITS_NE_CORNER) == Moves.BIT_NE) Render.quadTextured(rect, UFOG_NE);
if ((ufog & Sides.MASK_W) != 0) Render.quadTextured(rect, UFOG_W); if ((ufog & Moves.BIT_W) != 0) Render.quadTextured(rect, UFOG_W);
if ((ufog & Sides.MASK_E) != 0) Render.quadTextured(rect, UFOG_E); if ((ufog & Moves.BIT_E) != 0) Render.quadTextured(rect, UFOG_E);
if ((ufog & Sides.SW_CORNER) == Sides.MASK_SW) Render.quadTextured(rect, UFOG_SW); if ((ufog & Moves.BITS_SW_CORNER) == Moves.BIT_SW) Render.quadTextured(rect, UFOG_SW);
if ((ufog & Sides.MASK_S) != 0) Render.quadTextured(rect, UFOG_S); if ((ufog & Moves.BIT_S) != 0) Render.quadTextured(rect, UFOG_S);
if ((ufog & Sides.SE_CORNER) == Sides.MASK_SE) Render.quadTextured(rect, UFOG_SE); if ((ufog & Moves.BITS_SE_CORNER) == Moves.BIT_SE) Render.quadTextured(rect, UFOG_SE);
} }

@ -2,8 +2,6 @@ package mightypork.rogue.world.tile;
import mightypork.gamecore.util.math.color.Color; import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.color.pal.PAL16;
import mightypork.gamecore.util.math.color.pal.RGB;
/** /**
@ -14,25 +12,25 @@ import mightypork.gamecore.util.math.color.pal.RGB;
public enum TileType public enum TileType
{ {
/** No tile */ /** No tile */
NULL(RGB.NONE, false), NULL(TileColors.NULL, false),
/** Floor tile */ /** Floor tile */
FLOOR(RGB.GRAY_DARK, true), FLOOR(TileColors.FLOOR, true),
/** Wall tile */ /** Wall tile */
WALL(RGB.GRAY_LIGHT, false), WALL(TileColors.WALL, false),
/** Door/gate tile */ /** Door/gate tile */
DOOR(PAL16.NEWPOOP, true), DOOR(TileColors.DOOR, true),
/** Passage (ie secret door) */ /** Passage (ie secret door) */
PASSAGE(RGB.GRAY, true), PASSAGE(TileColors.COLLAPSED_WALL, true),
/** Stairs */ /** Stairs */
STAIRS(RGB.CYAN, false); STAIRS(TileColors.WALL, false);
private final Color mapColor; private final Color mapColor;
private final boolean potentiallyWalkable; private final boolean potentiallyWalkable;
private TileType(Color mapColor, boolean potentiallyWalkable) private TileType(Color defaultMapColor, boolean potentiallyWalkable)
{ {
this.mapColor = mapColor; this.mapColor = defaultMapColor;
this.potentiallyWalkable = potentiallyWalkable; this.potentiallyWalkable = potentiallyWalkable;
} }

@ -27,6 +27,7 @@ public final class Tiles {
public static final TileModel BRICK_HIDDEN_DOOR = new TileModel(14, TileBrickSecretDoor.class); public static final TileModel BRICK_HIDDEN_DOOR = new TileModel(14, TileBrickSecretDoor.class);
public static final TileModel BRICK_ENTRANCE = new TileModel(15, TileBrickEntrance.class); public static final TileModel BRICK_ENTRANCE = new TileModel(15, TileBrickEntrance.class);
public static final TileModel BRICK_EXIT = new TileModel(16, TileBrickExit.class); public static final TileModel BRICK_EXIT = new TileModel(16, TileBrickExit.class);
public static final TileModel BRICK_CHEST = new TileModel(17, TileBrickChest.class);
public static void register(int id, TileModel model) public static void register(int id, TileModel model)

@ -0,0 +1,101 @@
package mightypork.rogue.world.tile.impl;
import java.io.IOException;
import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileType;
public abstract class TileBaseChest extends TileWithItems {
public static final double POST_OPEN_DURA = 0.3;
public boolean opened = false;
public boolean removed = false;
public double timeSinceOpen = 10000;
private int clicks = 1;
public TileBaseChest(TileModel model)
{
super(model);
}
@Override
public TileType getType()
{
return TileType.FLOOR;
}
@Override
public boolean isWalkable()
{
return removed;
}
@Override
protected boolean shouldRenderItems()
{
return removed;
}
@Override
public boolean onClick()
{
if (opened & removed) return false;
if (clicks > 0) {
clicks--;
if (clicks == 0) {
opened = true;
timeSinceOpen = 0;
getWorld().getConsole().msgOpenChest();
}
} else {
if (opened && !removed && timeSinceOpen > POST_OPEN_DURA) {
removed = true;
clicks--;
}
}
return true;
}
@Override
public void save(IonOutput out) throws IOException
{
super.save(out);
out.writeIntByte(clicks);
out.writeBoolean(opened);
out.writeBoolean(removed);
}
@Override
public void load(IonInput in) throws IOException
{
super.load(in);
clicks = in.readIntByte();
opened = in.readBoolean();
removed = in.readBoolean();
}
@Override
public void updateTile(double delta)
{
super.updateTile(delta);
if (opened && timeSinceOpen < 10000) timeSinceOpen += delta;
}
}

@ -2,7 +2,9 @@ package mightypork.rogue.world.tile.impl;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.color.Color;
import mightypork.rogue.world.events.WorldAscendRequest; import mightypork.rogue.world.events.WorldAscendRequest;
import mightypork.rogue.world.tile.TileColors;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
@ -31,4 +33,11 @@ public abstract class TileBaseEntrance extends TileBaseStairs {
{ {
return false; return false;
} }
@Override
public Color getMapColor()
{
return TileColors.ENTRANCE;
}
} }

@ -2,7 +2,9 @@ package mightypork.rogue.world.tile.impl;
import mightypork.gamecore.util.math.algo.Coord; import mightypork.gamecore.util.math.algo.Coord;
import mightypork.gamecore.util.math.color.Color;
import mightypork.rogue.world.events.WorldDescendRequest; import mightypork.rogue.world.events.WorldDescendRequest;
import mightypork.rogue.world.tile.TileColors;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
@ -31,4 +33,11 @@ public abstract class TileBaseExit extends TileBaseStairs {
{ {
return false; return false;
} }
@Override
public Color getMapColor()
{
return TileColors.EXIT;
}
} }

@ -6,16 +6,14 @@ import java.io.IOException;
import mightypork.gamecore.resources.textures.TxSheet; import mightypork.gamecore.resources.textures.TxSheet;
import mightypork.gamecore.util.ion.IonInput; import mightypork.gamecore.util.ion.IonInput;
import mightypork.gamecore.util.ion.IonOutput; import mightypork.gamecore.util.ion.IonOutput;
import mightypork.gamecore.util.math.Calc;
import mightypork.gamecore.util.math.color.Color; import mightypork.gamecore.util.math.color.Color;
import mightypork.gamecore.util.math.color.pal.RGB; import mightypork.rogue.world.tile.TileColors;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileType;
public abstract class TileBaseSecretDoor extends TileBaseDoor { public abstract class TileBaseSecretDoor extends TileBaseDoor {
private int clicks = Calc.randInt(2, 3); private int clicks = 2;
public TileBaseSecretDoor(TileModel model, TxSheet secret, TxSheet closed, TxSheet open) public TileBaseSecretDoor(TileModel model, TxSheet secret, TxSheet closed, TxSheet open)
@ -43,8 +41,8 @@ public abstract class TileBaseSecretDoor extends TileBaseDoor {
@Override @Override
public Color getMapColor() public Color getMapColor()
{ {
if (locked) return TileType.WALL.getMapColor(); if (locked) return TileColors.SECRET_DOOR_HIDDEN;
return RGB.PINK; return TileColors.SECRET_DOOR_REVEALED;
} }

@ -31,12 +31,20 @@ public abstract class TileWithItems extends Tile {
@Override @Override
public void renderExtra(TileRenderContext context) public void renderExtra(TileRenderContext context)
{ {
if ((isExplored() || !Config.RENDER_UFOG) && !items.isEmpty()) { super.renderExtra(context);
if ((isExplored() || !Config.RENDER_UFOG) && hasItem() && shouldRenderItems()) {
itemRenderer.render(items, context); itemRenderer.render(items, context);
} }
} }
protected boolean shouldRenderItems()
{
return true;
}
@Override @Override
public void updateTile(double delta) public void updateTile(double delta)
{ {

@ -0,0 +1,25 @@
package mightypork.rogue.world.tile.impl.brick;
import mightypork.rogue.Res;
import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.impl.TileBaseChest;
import mightypork.rogue.world.tile.render.ChestRenderer;
public class TileBrickChest extends TileBaseChest {
public TileBrickChest(TileModel model)
{
super(model);
}
@Override
protected TileRenderer makeRenderer()
{
return new ChestRenderer(this, Res.getTxQuad("tile.brick.floor"), Res.getTxQuad("tile.extra.chest.closed"), Res.getTxQuad("tile.extra.chest.open"));
}
}

@ -13,9 +13,9 @@ public class TileBrickDoor extends TileBaseDoor {
//@formatter:off //@formatter:off
super( super(
model, model,
Res.txs("tile.brick.door.closed"), // LOCKED Res.getTxSheet("tile.brick.door.closed"), // LOCKED
Res.txs("tile.brick.door.closed"), Res.getTxSheet("tile.brick.door.closed"),
Res.txs("tile.brick.door.open") Res.getTxSheet("tile.brick.door.open")
); );
//@formatter:on //@formatter:on
} }

@ -19,7 +19,7 @@ public class TileBrickEntrance extends TileBaseEntrance {
@Override @Override
protected TileRenderer makeRenderer() protected TileRenderer makeRenderer()
{ {
return new OneFrameTileRenderer(this, Res.txq("tile.brick.stairs.up")); return new OneFrameTileRenderer(this, Res.getTxQuad("tile.brick.stairs.up"));
} }
} }

@ -19,7 +19,7 @@ public class TileBrickExit extends TileBaseExit {
@Override @Override
protected TileRenderer makeRenderer() protected TileRenderer makeRenderer()
{ {
return new OneFrameTileRenderer(this, Res.txq("tile.brick.stairs.down")); return new OneFrameTileRenderer(this, Res.getTxQuad("tile.brick.stairs.down"));
} }
} }

@ -10,7 +10,7 @@ public class TileBrickFloor extends TileBaseFloor {
public TileBrickFloor(TileModel model) public TileBrickFloor(TileModel model)
{ {
super(model, Res.txs("tile.brick.floor")); super(model, Res.getTxSheet("tile.brick.floor"));
} }
} }

@ -10,7 +10,7 @@ public class TileBrickPassage extends TileBasePassage {
public TileBrickPassage(TileModel model) public TileBrickPassage(TileModel model)
{ {
super(model, Res.txs("tile.brick.passage")); super(model, Res.getTxSheet("tile.brick.passage"));
} }
} }

@ -13,9 +13,9 @@ public class TileBrickSecretDoor extends TileBaseSecretDoor {
//@formatter:off //@formatter:off
super( super(
model, model,
Res.txs("tile.brick.door.secret"), Res.getTxSheet("tile.brick.door.secret"),
Res.txs("tile.brick.door.closed"), Res.getTxSheet("tile.brick.door.closed"),
Res.txs("tile.brick.door.open") Res.getTxSheet("tile.brick.door.open")
); );
//@formatter:on //@formatter:on

@ -10,7 +10,7 @@ public class TileBrickWall extends TileBaseWall {
public TileBrickWall(TileModel model) public TileBrickWall(TileModel model)
{ {
super(model, Res.txs("tile.brick.wall")); super(model, Res.getTxSheet("tile.brick.wall"));
} }
} }

@ -0,0 +1,50 @@
package mightypork.rogue.world.tile.render;
import mightypork.gamecore.render.Render;
import mightypork.gamecore.resources.textures.TxQuad;
import mightypork.rogue.world.level.render.TileRenderContext;
import mightypork.rogue.world.tile.TileRenderer;
import mightypork.rogue.world.tile.impl.TileBaseChest;
public class ChestRenderer extends TileRenderer {
private final TxQuad txqFloor;
private final TxQuad txqChest;
private final TileBaseChest chestTile;
private final TxQuad txqChestOpen;
public ChestRenderer(TileBaseChest tile, TxQuad txq, TxQuad chest, TxQuad chestOpen)
{
super(tile);
this.chestTile = tile;
this.txqFloor = txq;
this.txqChest = chest;
this.txqChestOpen = chestOpen;
}
@Override
public void renderTile(TileRenderContext context)
{
Render.quadTextured(context.getRect(), txqFloor);
}
@Override
public void renderExtra(TileRenderContext context)
{
if (!chestTile.opened) {
Render.quadTextured(context.getRect(), txqChest);
} else {
if (!chestTile.removed) {
Render.quadTextured(context.getRect(), txqChestOpen);
}
}
}
}
Loading…
Cancel
Save