World gen rewrite, big cleanup, new items & Chest tile.
This commit is contained in:
@@ -21,7 +21,7 @@ import mightypork.gamecore.util.annot.DefaultImpl;
|
||||
import mightypork.gamecore.util.files.InstanceLock;
|
||||
import mightypork.gamecore.util.ion.Ion;
|
||||
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()
|
||||
{
|
||||
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.events.Destroyable;
|
||||
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 */
|
||||
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.
|
||||
@@ -180,13 +177,13 @@ final public class EventBus implements Destroyable, BusAccess {
|
||||
{
|
||||
assertLive();
|
||||
|
||||
final DelayedEvent adelay = event.getClass().getAnnotation(DelayedEvent.class);
|
||||
final DelayedEvent adelay = Utils.getAnnotation(event, DelayedEvent.class);
|
||||
if (adelay != null) {
|
||||
sendDelayed(event, adelay.delay());
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getClass().isAnnotationPresent(ImmediateEvent.class)) {
|
||||
if (Utils.hasAnnotation(event, ImmediateEvent.class)) {
|
||||
sendDirect(event);
|
||||
return;
|
||||
}
|
||||
@@ -364,7 +361,6 @@ final public class EventBus implements Destroyable, BusAccess {
|
||||
|
||||
for (int i = 0; i < 2; i++) { // two tries.
|
||||
|
||||
// channels.setBuffering(true);
|
||||
for (final EventChannel<?, ?> b : channels) {
|
||||
if (b.canBroadcast(event)) {
|
||||
accepted = true;
|
||||
@@ -373,7 +369,6 @@ final public class EventBus implements Destroyable, BusAccess {
|
||||
|
||||
if (event.isConsumed()) break;
|
||||
}
|
||||
// channels.setBuffering(false);
|
||||
|
||||
if (!accepted) if (addChannelForEvent(event)) continue;
|
||||
|
||||
@@ -388,7 +383,7 @@ final public class EventBus implements Destroyable, BusAccess {
|
||||
private boolean shallLog(BusEvent<?> event)
|
||||
{
|
||||
if (!detailedLogging) return false;
|
||||
if (event.getClass().isAnnotationPresent(NotLoggedEvent.class)) return false;
|
||||
if (Utils.hasAnnotation(event, NotLoggedEvent.class)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package mightypork.gamecore.util;
|
||||
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
|
||||
/**
|
||||
* Assorted utils
|
||||
*
|
||||
@@ -14,4 +17,32 @@ public final class Utils {
|
||||
t.start();
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* 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 IllegalValueException()
|
||||
@@ -25,10 +31,4 @@ public class IllegalValueException extends RuntimeException {
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Thrown by a map-like class when the key specified is already taken.
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class KeyAlreadyExistsException extends RuntimeException {
|
||||
|
||||
public KeyAlreadyExistsException()
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
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();
|
||||
|
||||
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.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;
|
||||
} 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;
|
||||
} 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
|
||||
*/
|
||||
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;
|
||||
return list.get(rand.nextInt(list.size()));
|
||||
@@ -718,4 +731,14 @@ public class Calc {
|
||||
|
||||
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;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
/**
|
||||
* Numeric range, able to generate random numbers and give min/max values.
|
||||
*
|
||||
@@ -71,7 +74,7 @@ public class Range {
|
||||
*/
|
||||
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()
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
+10
-10
@@ -16,18 +16,18 @@ import mightypork.gamecore.util.ion.IonOutput;
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class Step implements IonObjBinary, IonObjBundled {
|
||||
public class Move implements IonObjBinary, IonObjBundled {
|
||||
|
||||
public static final int ION_MARK = 254;
|
||||
|
||||
public static final Step NORTH = new Step(0, -1);
|
||||
public static final Step SOUTH = new Step(0, 1);
|
||||
public static final Step EAST = new Step(1, 0);
|
||||
public static final Step WEST = new Step(-1, 0);
|
||||
public static final Step NONE = new Step(0, 0);
|
||||
public static final Move NORTH = new Move(0, -1);
|
||||
public static final Move SOUTH = new Move(0, 1);
|
||||
public static final Move EAST = new Move(1, 0);
|
||||
public static final Move WEST = new Move(-1, 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;
|
||||
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 == 0 && y == 0) return NONE;
|
||||
|
||||
return new Step(x, y);
|
||||
return new Move(x, y);
|
||||
}
|
||||
|
||||
private byte x;
|
||||
private byte y;
|
||||
|
||||
|
||||
public Step()
|
||||
public Move()
|
||||
{
|
||||
// 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.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.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
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 {
|
||||
@@ -17,7 +18,7 @@ public abstract class FloodFill {
|
||||
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);
|
||||
|
||||
final Step[] sides = getSpreadSides();
|
||||
boolean forceSpreadNext = forceSpreadStart();
|
||||
|
||||
boolean limitReached = false;
|
||||
@@ -62,7 +62,7 @@ public abstract class FloodFill {
|
||||
|
||||
forceSpreadNext = false;
|
||||
|
||||
for (final Step spr : sides) {
|
||||
for (final Move spr : getSpreadSides()) {
|
||||
final Coord next = current.add(spr);
|
||||
if (activeNodes.contains(next) || foundNodes.contains(next)) continue;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
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.ManhattanHeuristic;
|
||||
|
||||
@@ -29,24 +29,24 @@ public abstract class PathFinder {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
if (path == null) return null;
|
||||
|
||||
final List<Step> out = new ArrayList<>();
|
||||
final List<Move> out = new ArrayList<>();
|
||||
|
||||
final Coord current = start.copy();
|
||||
for (final Coord c : path) {
|
||||
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.y = c.y;
|
||||
}
|
||||
@@ -76,8 +76,6 @@ public abstract class PathFinder {
|
||||
open.add(n);
|
||||
}
|
||||
|
||||
final Step[] walkDirs = getWalkSides();
|
||||
|
||||
Node current = null;
|
||||
|
||||
while (true) {
|
||||
@@ -93,7 +91,7 @@ public abstract class PathFinder {
|
||||
break;
|
||||
}
|
||||
|
||||
for (final Step go : walkDirs) {
|
||||
for (final Move go : getWalkSides()) {
|
||||
|
||||
final Coord c = current.pos.add(go);
|
||||
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 Step[] getWalkSides();
|
||||
protected abstract List<Move> getWalkSides();
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package mightypork.gamecore.util.math.algo.pathfinding;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
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
|
||||
protected Step[] getWalkSides()
|
||||
protected List<Move> getWalkSides()
|
||||
{
|
||||
return source.getWalkSides();
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import mightypork.gamecore.util.math.color.Color;
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public interface COMMODORE {
|
||||
public interface CMDR {
|
||||
|
||||
Color BLACK = Color.fromHex(0x040013);
|
||||
Color WHITE = Color.fromHex(0xFFFFFF);
|
||||
@@ -38,6 +38,7 @@ public class RGB {
|
||||
|
||||
public static final Color PINK = Color.fromHex(0xFF3FFC);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
public void execute()
|
||||
{
|
||||
Res.getEffect("gui.shutter").play(1);
|
||||
Res.getSoundEffect("gui.shutter").play(1);
|
||||
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));
|
||||
font.setDiscardRatio(6 / 16D, 2 / 16D);
|
||||
|
||||
// aliases based on concrete usage
|
||||
// aliases
|
||||
fonts.addAlias("thick", "press_start");
|
||||
|
||||
fonts.addAlias("thin", "battlenet");
|
||||
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.stairs.up", grid.makeQuad(0, 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
|
||||
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.club", grid.makeQuad(1, 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.bone", grid.makeQuad(5, 0));
|
||||
textures.add("item.cheese", grid.makeQuad(6, 0));
|
||||
textures.add("item.sandwich", grid.makeQuad(7, 0));
|
||||
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
|
||||
* @return sheet
|
||||
*/
|
||||
public static TxSheet txs(String key)
|
||||
public static TxSheet getTxSheet(String key)
|
||||
{
|
||||
return textures.getSheet(key);
|
||||
}
|
||||
@@ -204,19 +207,19 @@ public final class Res {
|
||||
* @param key
|
||||
* @return quad
|
||||
*/
|
||||
public static TxQuad txq(String key)
|
||||
public static TxQuad getTxQuad(String key)
|
||||
{
|
||||
return textures.getQuad(key);
|
||||
}
|
||||
|
||||
|
||||
public static LoopPlayer getLoop(String key)
|
||||
public static LoopPlayer getSoundLoop(String key)
|
||||
{
|
||||
return sounds.getLoop(key);
|
||||
}
|
||||
|
||||
|
||||
public static EffectPlayer getEffect(String key)
|
||||
public static EffectPlayer getSoundEffect(String key)
|
||||
{
|
||||
return sounds.getEffect(key);
|
||||
}
|
||||
|
||||
@@ -84,9 +84,9 @@ public class HudLayer extends ScreenLayer {
|
||||
final HeartBar hearts = new HeartBar(
|
||||
playerHealthTotal,
|
||||
playerHealthActive,
|
||||
Res.txq("hud.heart.on"),
|
||||
Res.txq("hud.heart.half"),
|
||||
Res.txq("hud.heart.off"),
|
||||
Res.getTxQuad("hud.heart.on"),
|
||||
Res.getTxQuad("hud.heart.half"),
|
||||
Res.getTxQuad("hud.heart.off"),
|
||||
AlignX.LEFT);
|
||||
//@formatter:on
|
||||
|
||||
@@ -117,13 +117,13 @@ public class HudLayer extends ScreenLayer {
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -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.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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public class IngameNav extends LayoutComponent {
|
||||
|
||||
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)
|
||||
{
|
||||
super();
|
||||
this.txBase = Res.txq("inv.slot.base");
|
||||
this.txSelected = Res.txq("inv.slot.selected");
|
||||
this.txBase = Res.getTxQuad("inv.slot.base");
|
||||
this.txSelected = Res.getTxQuad("inv.slot.selected");
|
||||
|
||||
this.index = index;
|
||||
this.slots = allSlots;
|
||||
|
||||
+3
-13
@@ -22,7 +22,7 @@ import mightypork.rogue.world.item.Item;
|
||||
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_ROW = 4;
|
||||
@@ -86,7 +86,7 @@ public class InvLayer extends ScreenLayer {
|
||||
}
|
||||
|
||||
|
||||
public InvLayer(final ScreenGame screen)
|
||||
public InventoryLayer(final ScreenGame screen)
|
||||
{
|
||||
super(screen);
|
||||
|
||||
@@ -200,17 +200,7 @@ public class InvLayer extends ScreenLayer {
|
||||
|
||||
final int selected = getSelectedSlot();
|
||||
if (selected != -1) {
|
||||
final PlayerFacade pl = WorldProvider.get().getPlayer();
|
||||
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
|
||||
}
|
||||
}
|
||||
WorldProvider.get().getPlayer().dropItem(selected);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -20,9 +20,9 @@ public class NavButton extends ClickableComponent {
|
||||
public NavButton(TxQuad fg)
|
||||
{
|
||||
super();
|
||||
this.base = Res.txq("nav.button.bg.base");
|
||||
this.hover = Res.txq("nav.button.bg.hover");
|
||||
this.down = Res.txq("nav.button.bg.down");
|
||||
this.base = Res.getTxQuad("nav.button.bg.base");
|
||||
this.hover = Res.getTxQuad("nav.button.bg.hover");
|
||||
this.down = Res.getTxQuad("nav.button.bg.down");
|
||||
this.fg = fg;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import mightypork.gamecore.gui.screens.LayeredScreen;
|
||||
import mightypork.gamecore.input.KeyStroke;
|
||||
import mightypork.gamecore.input.Keys;
|
||||
import mightypork.gamecore.logging.Log;
|
||||
import mightypork.gamecore.util.math.Calc;
|
||||
import mightypork.rogue.Config;
|
||||
import mightypork.rogue.GameStateManager.GameState;
|
||||
import mightypork.rogue.events.GameStateRequest;
|
||||
@@ -32,7 +31,7 @@ public class ScreenGame extends LayeredScreen {
|
||||
WORLD, INV;
|
||||
}
|
||||
|
||||
private InvLayer invLayer;
|
||||
private InventoryLayer invLayer;
|
||||
private HudLayer hudLayer;
|
||||
|
||||
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)
|
||||
@@ -175,7 +185,7 @@ public class ScreenGame extends LayeredScreen {
|
||||
{
|
||||
super(app);
|
||||
|
||||
addLayer(invLayer = new InvLayer(this));
|
||||
addLayer(invLayer = new InventoryLayer(this));
|
||||
invLayer.setEnabled(false);
|
||||
invLayer.setVisible(false);
|
||||
|
||||
@@ -187,29 +197,18 @@ public class ScreenGame extends LayeredScreen {
|
||||
worldLayer.setEnabled(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
|
||||
bindKey(new KeyStroke(Keys.P), actionTogglePause);
|
||||
bindKey(new KeyStroke(Keys.PAUSE), actionTogglePause);
|
||||
bindKey(new KeyStroke(Keys.SPACE), actionTogglePause);
|
||||
|
||||
bindKey(new KeyStroke(Keys.I), actionToggleInv);
|
||||
bindKey(new KeyStroke(Keys.D), actionDropLastPickedItem);
|
||||
bindKey(new KeyStroke(Keys.E), actionEat);
|
||||
bindKey(new KeyStroke(Keys.M), actionToggleMinimap);
|
||||
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.S, Keys.MOD_CONTROL), actionSave);
|
||||
|
||||
// add as actions - enableables.
|
||||
@@ -224,11 +223,12 @@ public class ScreenGame extends LayeredScreen {
|
||||
worldActions.add(actionSave);
|
||||
worldActions.add(actionLoad);
|
||||
worldActions.add(actionMenu);
|
||||
worldActions.add(actionDropLastPickedItem);
|
||||
|
||||
worldActions.setEnabled(true);
|
||||
|
||||
// TMP TODO remove
|
||||
bindKey(new KeyStroke(Keys.X), new Runnable() {
|
||||
// CHEAT - X-ray
|
||||
bindKey(new KeyStroke(Keys.F10, Keys.MOD_CONTROL), new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
|
||||
@@ -69,7 +69,7 @@ public class WorldConsoleRenderer extends BaseComponent {
|
||||
}
|
||||
|
||||
} 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);
|
||||
|
||||
int r = 0;
|
||||
final ImagePainter ip = new ImagePainter(Res.txq("logo"));
|
||||
final ImagePainter ip = new ImagePainter(Res.getTxQuad("logo"));
|
||||
ip.keepAspectRatio();
|
||||
layout.put(ip, r, 0, 4, 1);
|
||||
r += 5;
|
||||
|
||||
@@ -162,6 +162,7 @@ public class WorldSlot extends ConstraintLayout {
|
||||
|
||||
if (!file.exists()) {
|
||||
label = "<empty>";
|
||||
worldBundle = null;
|
||||
} else {
|
||||
try {
|
||||
worldBundle = Ion.fromFile(file);
|
||||
@@ -173,7 +174,8 @@ public class WorldSlot extends ConstraintLayout {
|
||||
delBtn.setVisible(true);
|
||||
delBtn.setEnabled(true);
|
||||
|
||||
} catch (final IOException e) {
|
||||
} catch (final Exception e) {
|
||||
Log.w("Error loading world save.", e);
|
||||
label = "<corrupt>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ public class Inventory implements IonObjBinary {
|
||||
|
||||
public static final short ION_MARK = 54;
|
||||
private Item[] items;
|
||||
private int lastAddIndex = 0;
|
||||
|
||||
|
||||
public Inventory(int size)
|
||||
@@ -87,6 +88,8 @@ public class Inventory implements IonObjBinary {
|
||||
*/
|
||||
public Item getItem(int i)
|
||||
{
|
||||
if (i < 0 || i > getSize()) return null;
|
||||
|
||||
verifyIndex(i);
|
||||
final Item itm = items[i];
|
||||
if (itm == null || itm.isEmpty()) return null;
|
||||
@@ -112,6 +115,7 @@ public class Inventory implements IonObjBinary {
|
||||
{
|
||||
verifyIndex(i);
|
||||
items[i] = item;
|
||||
lastAddIndex = i;
|
||||
}
|
||||
|
||||
|
||||
@@ -136,7 +140,10 @@ public class Inventory implements IonObjBinary {
|
||||
for (int i = 0; i < getSize(); i++) {
|
||||
final Item itm = getItem(i);
|
||||
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);
|
||||
if (itm == null) {
|
||||
setItem(i, stored.split(stored.getAmount())); // store a copy, empty the original item.
|
||||
lastAddIndex = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -167,6 +175,12 @@ public class Inventory implements IonObjBinary {
|
||||
}
|
||||
|
||||
|
||||
public int getLastAddIndex()
|
||||
{
|
||||
return lastAddIndex;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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.rogue.world.entity.Entity;
|
||||
import mightypork.rogue.world.entity.EntityType;
|
||||
@@ -50,25 +50,25 @@ public abstract class PlayerControl {
|
||||
|
||||
public void goNorth()
|
||||
{
|
||||
go(Step.NORTH);
|
||||
go(Move.NORTH);
|
||||
}
|
||||
|
||||
|
||||
public void goSouth()
|
||||
{
|
||||
go(Step.SOUTH);
|
||||
go(Move.SOUTH);
|
||||
}
|
||||
|
||||
|
||||
public void goEast()
|
||||
{
|
||||
go(Step.EAST);
|
||||
go(Move.EAST);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public abstract class PlayerControl {
|
||||
* @param side
|
||||
* @return
|
||||
*/
|
||||
public boolean clickTile(Step side)
|
||||
public boolean clickTile(Move side)
|
||||
{
|
||||
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().addPathStep(side);
|
||||
}
|
||||
|
||||
|
||||
public boolean tryGo(Step e)
|
||||
public boolean tryGo(Move e)
|
||||
{
|
||||
if (!canGo(e)) return false;
|
||||
go(e);
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
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.rogue.world.entity.Entity;
|
||||
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);
|
||||
}
|
||||
@@ -400,8 +400,32 @@ public class PlayerFacade {
|
||||
}
|
||||
|
||||
|
||||
public boolean canGoTo(Step side)
|
||||
public boolean canGoTo(Move 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
addMessage("You've picked up a " + item.getVisualName() + ".");
|
||||
addMessage("You've picked up " + addArticle(item.getVisualName()) + ".");
|
||||
lastPickupItem = item;
|
||||
timeSinceLastPickup = 0;
|
||||
}
|
||||
|
||||
|
||||
public void msgDroppedItem(Item item)
|
||||
{
|
||||
addMessage("You've dropped " + addArticle(item.getVisualName()) + ".");
|
||||
lastPickupItem = null;
|
||||
}
|
||||
|
||||
|
||||
public void msgWeaponBreak(Item item)
|
||||
{
|
||||
addMessage("Your " + item.getVisualName() + " has broken!");
|
||||
@@ -217,4 +224,26 @@ public class WorldConsole implements Updateable {
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import mightypork.gamecore.util.math.algo.Coord;
|
||||
import mightypork.gamecore.util.math.algo.Sides;
|
||||
import mightypork.gamecore.util.math.algo.Step;
|
||||
import mightypork.gamecore.util.math.algo.Move;
|
||||
import mightypork.gamecore.util.math.algo.Moves;
|
||||
import mightypork.gamecore.util.math.algo.pathfinding.Heuristic;
|
||||
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
|
||||
|
||||
@@ -53,9 +55,9 @@ public class EntityPathFinder extends PathFinder {
|
||||
|
||||
|
||||
@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);
|
||||
|
||||
setAttackTime(0.7);
|
||||
setAttackTime(0.2);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getAttackStrength()
|
||||
{
|
||||
return Calc.randInt(5, 11);
|
||||
return Calc.randInt(1, 6);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,6 @@ public class BossRatAi extends GrayRatAi {
|
||||
@Override
|
||||
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.math.Calc;
|
||||
import mightypork.gamecore.util.math.algo.Coord;
|
||||
import mightypork.gamecore.util.math.algo.Sides;
|
||||
import mightypork.gamecore.util.math.algo.Step;
|
||||
import mightypork.gamecore.util.math.algo.Move;
|
||||
import mightypork.gamecore.util.math.algo.Moves;
|
||||
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
|
||||
import mightypork.gamecore.util.math.algo.pathfinding.PathFinderProxy;
|
||||
import mightypork.rogue.world.entity.AiTimer;
|
||||
@@ -65,7 +65,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
if (entity.pos.isMoving()) return;
|
||||
|
||||
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;
|
||||
|
||||
@@ -280,7 +280,7 @@ public class MonsterAi extends EntityModule implements EntityMoveListener {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<Step> preyPath = getPathToPrey(prey);
|
||||
final List<Move> preyPath = getPathToPrey(prey);
|
||||
|
||||
if (preyPath == null || preyPath.size() > getPreyAbandonDistance()) {
|
||||
stopChasing();
|
||||
|
||||
@@ -10,7 +10,7 @@ import java.util.Set;
|
||||
|
||||
import mightypork.gamecore.util.ion.IonBundle;
|
||||
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.rogue.world.entity.Entity;
|
||||
import mightypork.rogue.world.entity.EntityModule;
|
||||
@@ -22,7 +22,7 @@ public class EntityModulePosition extends EntityModule {
|
||||
private final Coord lastPos = new Coord(0, 0);
|
||||
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 double stepTime = 0.5;
|
||||
|
||||
@@ -136,7 +136,7 @@ public class EntityModulePosition extends EntityModule {
|
||||
|
||||
walking = true;
|
||||
|
||||
final Step step = path.poll();
|
||||
final Move step = path.poll();
|
||||
|
||||
final Coord planned = entityPos.getCoord().add(step.toCoord());
|
||||
|
||||
@@ -177,7 +177,7 @@ public class EntityModulePosition extends EntityModule {
|
||||
*
|
||||
* @param step
|
||||
*/
|
||||
public void addStep(Step step)
|
||||
public void addStep(Move step)
|
||||
{
|
||||
if (path.isEmpty() && !canGoTo(step)) return;
|
||||
|
||||
@@ -203,7 +203,7 @@ public class EntityModulePosition extends EntityModule {
|
||||
public boolean navigateTo(Coord target)
|
||||
{
|
||||
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;
|
||||
cancelPath();
|
||||
@@ -228,7 +228,7 @@ public class EntityModulePosition extends EntityModule {
|
||||
*
|
||||
* @param path steps
|
||||
*/
|
||||
public void addSteps(List<Step> path)
|
||||
public void addSteps(List<Move> 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));
|
||||
}
|
||||
|
||||
|
||||
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.math.Easing;
|
||||
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.VectConst;
|
||||
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());
|
||||
walkOffset.setTo(-step.x(), -step.y());
|
||||
|
||||
@@ -37,7 +37,7 @@ public class EntityRendererMobLR extends EntityRenderer {
|
||||
public EntityRendererMobLR(Entity entity, String sheetKey)
|
||||
{
|
||||
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 chest();
|
||||
}
|
||||
|
||||
@@ -13,5 +13,5 @@ import mightypork.gamecore.util.math.algo.Coord;
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
+3
-3
@@ -5,17 +5,17 @@ import mightypork.gamecore.util.math.algo.Coord;
|
||||
|
||||
|
||||
/**
|
||||
* Room description
|
||||
* Room description entry for {@link ScratchMap}
|
||||
*
|
||||
* @author MightyPork
|
||||
*/
|
||||
public class RoomDesc {
|
||||
public class RoomEntry {
|
||||
|
||||
final Coord min;
|
||||
final Coord max;
|
||||
|
||||
|
||||
public RoomDesc(Coord min, Coord max)
|
||||
public RoomEntry(Coord min, Coord max)
|
||||
{
|
||||
super();
|
||||
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.util.math.Calc;
|
||||
import mightypork.gamecore.util.math.algo.Coord;
|
||||
import mightypork.gamecore.util.math.algo.Sides;
|
||||
import mightypork.gamecore.util.math.algo.Step;
|
||||
import mightypork.gamecore.util.math.algo.Move;
|
||||
import mightypork.gamecore.util.math.algo.Moves;
|
||||
import mightypork.gamecore.util.math.algo.pathfinding.Heuristic;
|
||||
import mightypork.gamecore.util.math.algo.pathfinding.PathFinder;
|
||||
import mightypork.rogue.world.entity.Entity;
|
||||
@@ -33,7 +33,7 @@ public class ScratchMap {
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
private final List<RoomDesc> rooms = new ArrayList<>();
|
||||
private final List<RoomEntry> rooms = new ArrayList<>();
|
||||
|
||||
/** Coords to connect with corridors */
|
||||
private final List<Coord> nodes = new ArrayList<>();
|
||||
@@ -96,9 +96,9 @@ public class ScratchMap {
|
||||
|
||||
|
||||
@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);
|
||||
|
||||
int failed = 0;
|
||||
|
||||
int failed_total = 0;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
if (rooms.size() > 0) minimizeBounds();
|
||||
|
||||
final int sizeX = genMax.x - genMin.x;
|
||||
final int sizeY = genMax.y - genMin.y;
|
||||
final Coord roomPos = Coord.make(0, 0);
|
||||
|
||||
center.x = genMin.x + rand.nextInt(sizeX);
|
||||
center.y = genMin.y + rand.nextInt(sizeY);
|
||||
int failed = 0;
|
||||
int failed_total = 0;
|
||||
|
||||
switch (rand.nextInt(4)) {
|
||||
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);
|
||||
while (true) {
|
||||
|
||||
genMin.x = Math.min(genMin.x, rd.min.x);
|
||||
genMin.y = Math.min(genMin.y, rd.min.y);
|
||||
final int sizeX = genMax.x - genMin.x;
|
||||
final int sizeY = genMax.y - genMin.y;
|
||||
|
||||
genMax.x = Math.max(genMax.x, rd.max.x);
|
||||
genMax.y = Math.max(genMax.y, rd.max.y);
|
||||
clampBounds();
|
||||
roomPos.x = genMin.x + rand.nextInt(sizeX + 1);
|
||||
roomPos.y = genMin.y + rand.nextInt(sizeY + 1);
|
||||
|
||||
nodes.add(center);
|
||||
// Log.f3("Placed room (failed " + failed_total + " x).");
|
||||
|
||||
return true;
|
||||
} else {
|
||||
failed++;
|
||||
failed_total++;
|
||||
|
||||
if (failed_total > 1000) {
|
||||
return false;
|
||||
switch (rand.nextInt(4)) {
|
||||
case 0:
|
||||
roomPos.x += (failed_total / 35);
|
||||
break;
|
||||
case 1:
|
||||
roomPos.x -= (failed_total / 35);
|
||||
break;
|
||||
case 2:
|
||||
roomPos.y += (failed_total / 35);
|
||||
break;
|
||||
case 3:
|
||||
roomPos.y -= (failed_total / 35);
|
||||
}
|
||||
|
||||
if (failed > 300) {
|
||||
Log.w("Faild to build room.");
|
||||
if (critical) {
|
||||
|
||||
genMin.x -= 5;
|
||||
genMin.y -= 5;
|
||||
genMax.x += 5;
|
||||
genMax.y += 5;
|
||||
clampBounds();
|
||||
|
||||
failed = 0;
|
||||
Log.f3("Trying again.");
|
||||
continue;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
final RoomEntry rd = rb.buildRoom(this, theme, rand, roomPos);
|
||||
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);
|
||||
genMax.y = Math.max(genMax.y, rd.max.y);
|
||||
clampBounds();
|
||||
|
||||
nodes.add(roomPos);
|
||||
|
||||
return;
|
||||
|
||||
} 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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (!isIn(min) || !isIn(max)) return false;
|
||||
for (final RoomDesc r : rooms) {
|
||||
for (final RoomEntry r : rooms) {
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
byte walls = 0;
|
||||
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 (getTile(cc).isWall()) {
|
||||
walls |= Sides.bit(i);
|
||||
walls |= Moves.getBit(i);
|
||||
}
|
||||
}
|
||||
return walls;
|
||||
@@ -412,11 +448,11 @@ public class ScratchMap {
|
||||
{
|
||||
byte floors = 0;
|
||||
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 (getTile(cc).isFloor()) {
|
||||
floors |= Sides.bit(i);
|
||||
floors |= Moves.getBit(i);
|
||||
}
|
||||
}
|
||||
return floors;
|
||||
@@ -427,11 +463,11 @@ public class ScratchMap {
|
||||
{
|
||||
byte doors = 0;
|
||||
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 (getTile(cc).isDoor()) {
|
||||
doors |= Sides.bit(i);
|
||||
doors |= Moves.getBit(i);
|
||||
}
|
||||
}
|
||||
return doors;
|
||||
@@ -442,16 +478,119 @@ public class ScratchMap {
|
||||
{
|
||||
byte nils = 0;
|
||||
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()) {
|
||||
nils |= Sides.bit(i);
|
||||
nils |= Moves.getBit(i);
|
||||
}
|
||||
}
|
||||
return nils;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fix generator glitches and reduce size to the actual used size
|
||||
*/
|
||||
public void fixGlitches()
|
||||
{
|
||||
final Tile[][] out = new Tile[height][width];
|
||||
|
||||
// bounds will be adjusted by the actual tiles in the map
|
||||
genMin.x = width;
|
||||
genMin.y = height;
|
||||
genMax.x = 0;
|
||||
genMax.y = 0;
|
||||
|
||||
final Coord c = Coord.make(0, 0);
|
||||
for (c.x = 0; c.x < width; c.x++) {
|
||||
for (c.y = 0; c.y < height; c.y++) {
|
||||
|
||||
final Tile t = getTile(c);
|
||||
final boolean isNull = t.isNull();
|
||||
|
||||
final boolean isDoor = !isNull && t.isDoor();
|
||||
final boolean isFloor = !isNull && t.isFloor();
|
||||
final boolean isWall = !isNull && t.isWall();
|
||||
|
||||
// bitmasks
|
||||
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;
|
||||
}
|
||||
|
||||
if (isFloor && (nils & Moves.BITS_CARDINAL) != 0) {
|
||||
toWall = true; // floor with adjacent cardinal null
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNull && (floors & Moves.BITS_DIAGONAL) != 0) {
|
||||
toWall = true; // null with adjacent diagonal floor
|
||||
break;
|
||||
}
|
||||
|
||||
if (isDoor) {
|
||||
|
||||
if (Calc.countBits((byte) (floors & Moves.BITS_CARDINAL)) < 2) {
|
||||
toWall = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Calc.countBits((byte) (walls & Moves.BITS_CARDINAL)) > 2) {
|
||||
toWall = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Calc.countBits((byte) (floors & Moves.BITS_CARDINAL)) > 2) {
|
||||
toFloor = true;
|
||||
break;
|
||||
}
|
||||
|
||||
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 ((floors & Moves.BITS_SW_CORNER) == Moves.BITS_SW_CORNER) toWall = true;
|
||||
if ((floors & Moves.BITS_SE_CORNER) == Moves.BITS_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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write tiles and entities into a level
|
||||
*
|
||||
* @param level the level
|
||||
*/
|
||||
public void writeToLevel(Level level)
|
||||
{
|
||||
if (level.getWorld() == null) {
|
||||
@@ -462,85 +601,6 @@ public class ScratchMap {
|
||||
final Coord c = Coord.make(0, 0);
|
||||
final Coord c1 = Coord.make(0, 0);
|
||||
|
||||
if (FIX_GLITCHES) {
|
||||
|
||||
final Tile[][] out = new Tile[height][width];
|
||||
|
||||
for (c.x = 0; c.x < width; c.x++) {
|
||||
for (c.y = 0; c.y < height; c.y++) {
|
||||
|
||||
final Tile t = getTile(c);
|
||||
final boolean isNull = t.isNull();
|
||||
|
||||
final boolean isDoor = !isNull && t.isDoor();
|
||||
final boolean isFloor = !isNull && t.isFloor();
|
||||
final boolean isWall = !isNull && t.isWall();
|
||||
|
||||
// bitmasks
|
||||
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;
|
||||
}
|
||||
|
||||
if (isFloor && (nils & Sides.MASK_CARDINAL) != 0) {
|
||||
toWall = true; // floor with adjacent cardinal null
|
||||
break;
|
||||
}
|
||||
|
||||
if (isNull && (floors & Sides.MASK_DIAGONAL) != 0) {
|
||||
toWall = true; // null with adjacent diagonal floor
|
||||
break;
|
||||
}
|
||||
|
||||
if (isDoor) {
|
||||
|
||||
if (countBits((byte) (floors & Sides.MASK_CARDINAL)) < 2) {
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
map = out;
|
||||
}
|
||||
|
||||
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++) {
|
||||
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;
|
||||
|
||||
final Tile t = getTile(pos);
|
||||
if (!canStack && t.hasItem()) return false;
|
||||
if (t.dropItem(item)) return true;
|
||||
|
||||
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();
|
||||
|
||||
for (int i = 0; i < tries; i++) {
|
||||
pos.x = min.x + rand.nextInt(max.x - min.x);
|
||||
pos.y = min.y + rand.nextInt(max.y - min.y);
|
||||
if (putItem(item, pos)) return true;
|
||||
for (int i = 0; i < 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, 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;
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
|
||||
for (int i = 0; i < tries; i++) {
|
||||
pos.x = min.x + rand.nextInt(max.x - min.x);
|
||||
pos.y = min.y + rand.nextInt(max.y - min.y);
|
||||
pos.x = Calc.randInt(rand, min.x, max.x);
|
||||
pos.y = Calc.randInt(rand, min.y, max.y);
|
||||
if (!isIn(pos)) continue;
|
||||
|
||||
if (putEntity(entity, pos)) return true;
|
||||
if (addEntity(entity, pos)) return true;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
@@ -1,9 +1,21 @@
|
||||
package mightypork.rogue.world.gen;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
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.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 {
|
||||
@@ -15,20 +27,127 @@ public class WorldCreator {
|
||||
{
|
||||
synchronized (rand) {
|
||||
rand.setSeed(seed);
|
||||
final MapTheme theme = new ThemeBrick();
|
||||
|
||||
final World w = new World();
|
||||
w.setSeed(seed);
|
||||
|
||||
final int count = 7;
|
||||
final LevelBuilder levelBuilders[] = new LevelBuilder[7];
|
||||
|
||||
for (int lvl = 1; lvl <= count; lvl++) {
|
||||
w.addLevel(LevelGenerator.build(w, rand.nextLong(), lvl, LevelGenerator.DUNGEON_THEME, lvl == count));
|
||||
// build the level rooms
|
||||
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();
|
||||
|
||||
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.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.RoomBuilder;
|
||||
import mightypork.rogue.world.gen.RoomDesc;
|
||||
import mightypork.rogue.world.gen.RoomEntry;
|
||||
import mightypork.rogue.world.gen.ScratchMap;
|
||||
import mightypork.rogue.world.gen.TileProtectLevel;
|
||||
import mightypork.rogue.world.tile.TileModel;
|
||||
@@ -17,7 +17,7 @@ import mightypork.rogue.world.tile.TileModel;
|
||||
public abstract class AbstractRectRoom implements RoomBuilder {
|
||||
|
||||
@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
|
||||
final Coord innerSize = getInnerSize(rand);
|
||||
@@ -42,7 +42,7 @@ public abstract class AbstractRectRoom implements RoomBuilder {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if ((map.findDoors(door) & Sides.MASK_CARDINAL) == 0) {
|
||||
if ((map.findDoors(door) & Moves.BITS_CARDINAL) == 0) {
|
||||
map.set(door, getDoorType(theme, rand));
|
||||
i++; // increment pointer
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ 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.entity.Entities;
|
||||
import mightypork.rogue.world.entity.Entity;
|
||||
@@ -17,21 +16,42 @@ public class BossRoom extends SecretRoom {
|
||||
@Override
|
||||
protected int getDoorCount(Random rand)
|
||||
{
|
||||
return Calc.randInt(rand, 1, 3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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();
|
||||
if (!map.putEntityInArea(boss, min, max, 100)) {
|
||||
|
||||
// just place it anywhere then
|
||||
if (!map.putEntityInMap(boss, 100)) {
|
||||
throw new WorldGenError("Could not place boss.");
|
||||
}
|
||||
|
||||
if (!map.addEntity(boss, bossPos)) {
|
||||
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.rogue.world.gen.MapTheme;
|
||||
import mightypork.rogue.world.gen.RoomBuilder;
|
||||
import mightypork.rogue.world.gen.RoomDesc;
|
||||
import mightypork.rogue.world.gen.RoomEntry;
|
||||
import mightypork.rogue.world.gen.ScratchMap;
|
||||
|
||||
|
||||
public class DeadEndRoom implements RoomBuilder {
|
||||
|
||||
@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 high = center;
|
||||
@@ -21,6 +21,6 @@ public class DeadEndRoom implements RoomBuilder {
|
||||
|
||||
map.set(center, theme.floor());
|
||||
|
||||
return new RoomDesc(low, high);
|
||||
return new RoomEntry(low, high);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-11
@@ -9,30 +9,33 @@ import mightypork.rogue.world.gen.MapTheme;
|
||||
import mightypork.rogue.world.gen.ScratchMap;
|
||||
import mightypork.rogue.world.gen.WorldGenError;
|
||||
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
|
||||
protected int getDoorCount(Random rand)
|
||||
{
|
||||
return Calc.randInt(rand, 1, 3);
|
||||
return Calc.randInt(rand, 1, 4);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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.putItemInArea(heart, min, max, 100)) {
|
||||
if (!map.putItemInMap(heart, 100)) {
|
||||
throw new WorldGenError("Could not place heart piece.");
|
||||
}
|
||||
|
||||
}
|
||||
if (!map.addItem(item, center)) {
|
||||
throw new WorldGenError("Could not place item in chest.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@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.events.KeyEvent;
|
||||
import mightypork.gamecore.input.events.KeyListener;
|
||||
import mightypork.gamecore.util.math.algo.Sides;
|
||||
import mightypork.gamecore.util.math.algo.Step;
|
||||
import mightypork.gamecore.util.math.algo.Move;
|
||||
import mightypork.gamecore.util.math.algo.Moves;
|
||||
import mightypork.gamecore.util.math.constraints.vect.Vect;
|
||||
import mightypork.rogue.world.entity.impl.PlayerEntity;
|
||||
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 {
|
||||
|
||||
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)
|
||||
@@ -72,7 +72,7 @@ public class MIPKeyboard extends MapInteractionPlugin implements PlayerStepEndLi
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (InputSystem.isKeyDown(keys[i])) {
|
||||
|
||||
final Step side = sides[i];
|
||||
final Move side = sides[i];
|
||||
if (mapView.plc.canGo(side)) {
|
||||
mapView.plc.go(side);
|
||||
return true;
|
||||
|
||||
@@ -6,7 +6,7 @@ import mightypork.gamecore.input.InputSystem;
|
||||
import mightypork.gamecore.util.math.Calc.Deg;
|
||||
import mightypork.gamecore.util.math.Polar;
|
||||
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.rogue.world.entity.impl.PlayerEntity;
|
||||
import mightypork.rogue.world.events.PlayerStepEndListener;
|
||||
@@ -97,16 +97,16 @@ public class MIPMouse extends MapInteractionPlugin implements PlayerStepEndListe
|
||||
|
||||
switch (dir) {
|
||||
case 0:
|
||||
return mapView.plc.tryGo(Sides.E);
|
||||
return mapView.plc.tryGo(Moves.E);
|
||||
|
||||
case 1:
|
||||
return mapView.plc.tryGo(Sides.S);
|
||||
return mapView.plc.tryGo(Moves.S);
|
||||
|
||||
case 2:
|
||||
return mapView.plc.tryGo(Sides.W);
|
||||
return mapView.plc.tryGo(Moves.W);
|
||||
|
||||
case 3:
|
||||
return mapView.plc.tryGo(Sides.N);
|
||||
return mapView.plc.tryGo(Moves.N);
|
||||
}
|
||||
|
||||
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.ItemMeat;
|
||||
import mightypork.rogue.world.item.impl.food.ItemSandwich;
|
||||
import mightypork.rogue.world.item.impl.weapons.ItemBone;
|
||||
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;
|
||||
import mightypork.rogue.world.item.impl.weapons.*;
|
||||
|
||||
|
||||
/**
|
||||
@@ -31,10 +27,12 @@ public final class Items {
|
||||
public static final ItemModel BONE = new ItemModel(3, ItemBone.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 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 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 TWIG = new ItemModel(10, ItemTwig.class);
|
||||
public static final ItemModel KNIFE = new ItemModel(11, ItemKnife.class);
|
||||
|
||||
|
||||
public static void register(int id, ItemModel model)
|
||||
|
||||
@@ -21,7 +21,7 @@ public class ItemHeartPiece extends Item {
|
||||
@Override
|
||||
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
|
||||
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
|
||||
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
|
||||
protected ItemRenderer makeRenderer()
|
||||
{
|
||||
return new QuadItemRenderer(this, Res.txq("item.sandwich"));
|
||||
return new QuadItemRenderer(this, Res.getTxQuad("item.sandwich"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
+5
-5
@@ -8,9 +8,9 @@ import mightypork.rogue.world.item.impl.ItemBaseWeapon;
|
||||
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);
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class ItemHammer extends ItemBaseWeapon {
|
||||
@Override
|
||||
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
|
||||
public int getMaxUses()
|
||||
{
|
||||
return 100;
|
||||
return 70;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getVisualName()
|
||||
{
|
||||
return "Hammer";
|
||||
return "Axe";
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class ItemBone extends ItemBaseWeapon {
|
||||
@Override
|
||||
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
|
||||
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";
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -8,9 +8,9 @@ import mightypork.rogue.world.item.impl.ItemBaseWeapon;
|
||||
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);
|
||||
}
|
||||
@@ -19,7 +19,7 @@ public class ItemStone extends ItemBaseWeapon {
|
||||
@Override
|
||||
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
|
||||
protected ItemRenderer makeRenderer()
|
||||
{
|
||||
return new QuadItemRenderer(this, Res.txq("item.sword"));
|
||||
return new QuadItemRenderer(this, Res.getTxQuad("item.sword"));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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.math.Calc;
|
||||
import mightypork.gamecore.util.math.algo.Coord;
|
||||
import mightypork.gamecore.util.math.algo.Sides;
|
||||
import mightypork.gamecore.util.math.algo.Step;
|
||||
import mightypork.gamecore.util.math.algo.Move;
|
||||
import mightypork.gamecore.util.math.algo.Moves;
|
||||
import mightypork.gamecore.util.math.algo.floodfill.FloodFill;
|
||||
import mightypork.gamecore.util.math.constraints.vect.Vect;
|
||||
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() {
|
||||
|
||||
@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.Step;
|
||||
import mightypork.gamecore.util.math.algo.Move;
|
||||
import mightypork.gamecore.util.math.constraints.rect.Rect;
|
||||
import mightypork.gamecore.util.math.constraints.rect.proxy.RectBound;
|
||||
import mightypork.gamecore.util.math.noise.NoiseGen;
|
||||
@@ -46,7 +46,7 @@ public final class TileRenderContext extends MapRenderContext implements RectBou
|
||||
* @param offset offsets
|
||||
* @return the tile at that position
|
||||
*/
|
||||
public Tile getAdjacentTile(Step offset)
|
||||
public Tile getAdjacentTile(Move offset)
|
||||
{
|
||||
return map.getTile(pos.add(offset));
|
||||
}
|
||||
|
||||
@@ -98,6 +98,8 @@ public abstract class Tile implements BusAccess, IonObjBlob {
|
||||
@DefaultImpl
|
||||
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.render.Render;
|
||||
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.rogue.Res;
|
||||
import mightypork.rogue.world.level.render.TileRenderContext;
|
||||
@@ -44,24 +45,24 @@ public abstract class TileRenderer implements Updateable {
|
||||
this.tile = tile;
|
||||
|
||||
if (!inited) {
|
||||
SH_N = Res.txq("tile.shadow.n");
|
||||
SH_S = Res.txq("tile.shadow.s");
|
||||
SH_E = Res.txq("tile.shadow.e");
|
||||
SH_W = Res.txq("tile.shadow.w");
|
||||
SH_NW = Res.txq("tile.shadow.nw");
|
||||
SH_NE = Res.txq("tile.shadow.ne");
|
||||
SH_SW = Res.txq("tile.shadow.sw");
|
||||
SH_SE = Res.txq("tile.shadow.se");
|
||||
SH_N = Res.getTxQuad("tile.shadow.n");
|
||||
SH_S = Res.getTxQuad("tile.shadow.s");
|
||||
SH_E = Res.getTxQuad("tile.shadow.e");
|
||||
SH_W = Res.getTxQuad("tile.shadow.w");
|
||||
SH_NW = Res.getTxQuad("tile.shadow.nw");
|
||||
SH_NE = Res.getTxQuad("tile.shadow.ne");
|
||||
SH_SW = Res.getTxQuad("tile.shadow.sw");
|
||||
SH_SE = Res.getTxQuad("tile.shadow.se");
|
||||
|
||||
UFOG_N = Res.txq("tile.ufog.n");
|
||||
UFOG_S = Res.txq("tile.ufog.s");
|
||||
UFOG_E = Res.txq("tile.ufog.e");
|
||||
UFOG_W = Res.txq("tile.ufog.w");
|
||||
UFOG_NW = Res.txq("tile.ufog.nw");
|
||||
UFOG_NE = Res.txq("tile.ufog.ne");
|
||||
UFOG_SW = Res.txq("tile.ufog.sw");
|
||||
UFOG_SE = Res.txq("tile.ufog.se");
|
||||
UFOG_FULL = Res.txq("tile.ufog.full");
|
||||
UFOG_N = Res.getTxQuad("tile.ufog.n");
|
||||
UFOG_S = Res.getTxQuad("tile.ufog.s");
|
||||
UFOG_E = Res.getTxQuad("tile.ufog.e");
|
||||
UFOG_W = Res.getTxQuad("tile.ufog.w");
|
||||
UFOG_NW = Res.getTxQuad("tile.ufog.nw");
|
||||
UFOG_NE = Res.getTxQuad("tile.ufog.ne");
|
||||
UFOG_SW = Res.getTxQuad("tile.ufog.sw");
|
||||
UFOG_SE = Res.getTxQuad("tile.ufog.se");
|
||||
UFOG_FULL = Res.getTxQuad("tile.ufog.full");
|
||||
inited = true;
|
||||
}
|
||||
}
|
||||
@@ -78,9 +79,9 @@ public abstract class TileRenderer implements Updateable {
|
||||
shadows = 0; // reset the mask
|
||||
|
||||
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()) {
|
||||
shadows |= Sides.bit(i);
|
||||
shadows |= Moves.getBit(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,16 +91,22 @@ public abstract class TileRenderer implements Updateable {
|
||||
if (shadows == 0) return;
|
||||
final Rect rect = context.getRect();
|
||||
|
||||
if ((shadows & Sides.NW_CORNER) == Sides.MASK_NW) Render.quadTextured(rect, SH_NW);
|
||||
if ((shadows & Sides.MASK_N) != 0) Render.quadTextured(rect, SH_N);
|
||||
if ((shadows & Sides.NE_CORNER) == Sides.MASK_NE) Render.quadTextured(rect, SH_NE);
|
||||
if ((shadows & Moves.BITS_NW_CORNER) == Moves.BIT_NW) Render.quadTextured(rect, SH_NW);
|
||||
if ((shadows & Moves.BIT_N) != 0) Render.quadTextured(rect, SH_N);
|
||||
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 & Sides.MASK_E) != 0) Render.quadTextured(rect, SH_E);
|
||||
if ((shadows & Moves.BIT_W) != 0) Render.quadTextured(rect, SH_W);
|
||||
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 & Sides.MASK_S) != 0) Render.quadTextured(rect, SH_S);
|
||||
if ((shadows & Sides.SE_CORNER) == Sides.MASK_SE) Render.quadTextured(rect, SH_SE);
|
||||
if ((shadows & Moves.BITS_SW_CORNER) == Moves.BIT_SW) Render.quadTextured(rect, SH_SW);
|
||||
if ((shadows & Moves.BIT_S) != 0) Render.quadTextured(rect, SH_S);
|
||||
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;
|
||||
|
||||
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()) {
|
||||
ufog |= Sides.bit(i);
|
||||
ufog |= Moves.getBit(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (ufog == 0) return;
|
||||
|
||||
if ((ufog & Sides.NW_CORNER) == Sides.MASK_NW) Render.quadTextured(rect, UFOG_NW);
|
||||
if ((ufog & Sides.MASK_N) != 0) Render.quadTextured(rect, UFOG_N);
|
||||
if ((ufog & Sides.NE_CORNER) == Sides.MASK_NE) Render.quadTextured(rect, UFOG_NE);
|
||||
if ((ufog & Moves.BITS_NW_CORNER) == Moves.BIT_NW) Render.quadTextured(rect, UFOG_NW);
|
||||
if ((ufog & Moves.BIT_N) != 0) Render.quadTextured(rect, UFOG_N);
|
||||
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 & Sides.MASK_E) != 0) Render.quadTextured(rect, UFOG_E);
|
||||
if ((ufog & Moves.BIT_W) != 0) Render.quadTextured(rect, UFOG_W);
|
||||
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 & Sides.MASK_S) != 0) Render.quadTextured(rect, UFOG_S);
|
||||
if ((ufog & Sides.SE_CORNER) == Sides.MASK_SE) Render.quadTextured(rect, UFOG_SE);
|
||||
if ((ufog & Moves.BITS_SW_CORNER) == Moves.BIT_SW) Render.quadTextured(rect, UFOG_SW);
|
||||
if ((ufog & Moves.BIT_S) != 0) Render.quadTextured(rect, UFOG_S);
|
||||
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.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
|
||||
{
|
||||
/** No tile */
|
||||
NULL(RGB.NONE, false),
|
||||
NULL(TileColors.NULL, false),
|
||||
/** Floor tile */
|
||||
FLOOR(RGB.GRAY_DARK, true),
|
||||
FLOOR(TileColors.FLOOR, true),
|
||||
/** Wall tile */
|
||||
WALL(RGB.GRAY_LIGHT, false),
|
||||
WALL(TileColors.WALL, false),
|
||||
/** Door/gate tile */
|
||||
DOOR(PAL16.NEWPOOP, true),
|
||||
DOOR(TileColors.DOOR, true),
|
||||
/** Passage (ie secret door) */
|
||||
PASSAGE(RGB.GRAY, true),
|
||||
PASSAGE(TileColors.COLLAPSED_WALL, true),
|
||||
/** Stairs */
|
||||
STAIRS(RGB.CYAN, false);
|
||||
STAIRS(TileColors.WALL, false);
|
||||
|
||||
private final Color mapColor;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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_ENTRANCE = new TileModel(15, TileBrickEntrance.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)
|
||||
|
||||
@@ -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.color.Color;
|
||||
import mightypork.rogue.world.events.WorldAscendRequest;
|
||||
import mightypork.rogue.world.tile.TileColors;
|
||||
import mightypork.rogue.world.tile.TileModel;
|
||||
|
||||
|
||||
@@ -31,4 +33,11 @@ public abstract class TileBaseEntrance extends TileBaseStairs {
|
||||
{
|
||||
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.color.Color;
|
||||
import mightypork.rogue.world.events.WorldDescendRequest;
|
||||
import mightypork.rogue.world.tile.TileColors;
|
||||
import mightypork.rogue.world.tile.TileModel;
|
||||
|
||||
|
||||
@@ -31,4 +33,11 @@ public abstract class TileBaseExit extends TileBaseStairs {
|
||||
{
|
||||
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.util.ion.IonInput;
|
||||
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.pal.RGB;
|
||||
import mightypork.rogue.world.tile.TileColors;
|
||||
import mightypork.rogue.world.tile.TileModel;
|
||||
import mightypork.rogue.world.tile.TileType;
|
||||
|
||||
|
||||
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)
|
||||
@@ -43,8 +41,8 @@ public abstract class TileBaseSecretDoor extends TileBaseDoor {
|
||||
@Override
|
||||
public Color getMapColor()
|
||||
{
|
||||
if (locked) return TileType.WALL.getMapColor();
|
||||
return RGB.PINK;
|
||||
if (locked) return TileColors.SECRET_DOOR_HIDDEN;
|
||||
return TileColors.SECRET_DOOR_REVEALED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -31,12 +31,20 @@ public abstract class TileWithItems extends Tile {
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected boolean shouldRenderItems()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
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
|
||||
super(
|
||||
model,
|
||||
Res.txs("tile.brick.door.closed"), // LOCKED
|
||||
Res.txs("tile.brick.door.closed"),
|
||||
Res.txs("tile.brick.door.open")
|
||||
Res.getTxSheet("tile.brick.door.closed"), // LOCKED
|
||||
Res.getTxSheet("tile.brick.door.closed"),
|
||||
Res.getTxSheet("tile.brick.door.open")
|
||||
);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class TileBrickEntrance extends TileBaseEntrance {
|
||||
@Override
|
||||
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
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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
|
||||
super(
|
||||
model,
|
||||
Res.txs("tile.brick.door.secret"),
|
||||
Res.txs("tile.brick.door.closed"),
|
||||
Res.txs("tile.brick.door.open")
|
||||
Res.getTxSheet("tile.brick.door.secret"),
|
||||
Res.getTxSheet("tile.brick.door.closed"),
|
||||
Res.getTxSheet("tile.brick.door.open")
|
||||
);
|
||||
//@formatter:on
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ public class TileBrickWall extends TileBaseWall {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user