Compare commits

..

No commits in common. "stable" and "bottom-bar" have entirely different histories.

67 changed files with 764 additions and 1150 deletions

View File

@ -1,41 +0,0 @@
#!/usr/bin/env node
const { readdirSync, readFileSync } = require('fs');
const { resolve, parse, relative } = require('path');
const trimWhitespace = true;
const base = "./src";
let lines = 0;
let files = [];
function processDir(path) {
const children = readdirSync(path, {
withFileTypes: true
});
for(const entity of children) {
const { name } = entity
const full = resolve(path, name);
if(entity.isFile()) {
processFile(full);
} else if(entity.isDirectory()) {
processDir(full);
}
}
}
function processFile(path) {
const parsed = parse(path);
const rel = relative(resolve(base), path)
const type = parsed.ext;
const text = readFileSync(path);
console.log(path);
}
function printStats() {
console.log("")
}
processDir(base);
printStats();

View File

@ -21,7 +21,7 @@ public abstract class Game {
if(this.scene != null) {
this.scene.disable();
}
scene.enable(this);
scene.enable();
this.scene = scene;
}
@ -51,14 +51,6 @@ public abstract class Game {
}
}
public final float getAverageFPS() {
return averageFPS;
}
public final int getMeasuredFPS() {
return measuredFPS;
}
public abstract void updateViewMatrix(Matrix4f matrix);
public final void scrollUp() {

View File

@ -173,30 +173,6 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre
}
}
private final Vector2i getNextBoxDimensions() {
if(context.fixedSize) {
return context.box.dim.asInt();
} else {
return Vector2i.zero;
}
}
private LayoutStyle getDefaultLayoutStyle() {
if(context.fixedSize) {
if(context.horizontal) {
return LayoutStyle.shrink; // IDK if thats a good default...
} else {
return LayoutStyle.expandWidth;
}
} else {
if(context.horizontal) {
return LayoutStyle.normal;
} else {
return LayoutStyle.normal;
}
}
}
// === ELEMENTS ===
//
@ -271,26 +247,39 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre
}
protected boolean button(String text) {
return button(genButtonId(), text, getDefaultLayoutStyle());
return button(genButtonId(), text, false);
}
protected boolean button(String text, LayoutStyle style) {
return button(genButtonId(), text, style);
protected boolean button(String text, boolean expand) {
return button(genButtonId(), text, expand);
}
protected boolean button(String id, String text) {
return button(id, text, getDefaultLayoutStyle());
return button(id, text, false);
}
protected boolean button(String id, String text, LayoutStyle style) {
Vector2i position = getNextBoxLocation();
Vector2i availableSpace = getNextBoxDimensions();
protected boolean button(String id, String text, boolean expand) {
int h = 32;
if(expand && context.fixedSize) {
h = (int) context.box.h;
}
int w = (int) context.box.w;
if(context.horizontal && !context.fixedSize) {
w = 100;
}
int x = (int) context.box.x;
int y = (int) context.box.y;
Box buttonBox = new Box(
position,
availableSpace.x == 0 ? style.width : (float) Math.min(style.width, availableSpace.x),
availableSpace.y == 0 ? style.height : (float) Math.min(style.height, availableSpace.y)
);
if(!context.fixedSize) {
if(context.vertical()) {
y += (int) context.box.h;
} else {
x += (int) context.box.w;
}
}
Box buttonBox = new Box(x, y, w, h);
Button btn = getButton(id);
if(!context.hasRegisteredGuiArea) {
@ -298,8 +287,8 @@ public abstract class ImmediateUI extends GameObject implements IMouseCaptureAre
}
btn.setText(text);
btn.setPosition((int) buttonBox.x, (int) buttonBox.y);
btn.setSize((int) buttonBox.w, (int) buttonBox.h);
btn.setPosition(x, y);
btn.setSize(w, h);
btn.setLayer(getCurrentLayer());
adjustBox(buttonBox.w, buttonBox.h);

View File

@ -1,17 +0,0 @@
package xyz.valnet.engine.graphics;
public class LayoutStyle {
public int width = 100, height = 32;
public static LayoutStyle normal = LayoutStyle.sized(100, 32);
public static LayoutStyle expand = LayoutStyle.sized(Integer.MAX_VALUE, Integer.MAX_VALUE);
public static LayoutStyle shrink = LayoutStyle.sized(0, 0);
public static LayoutStyle expandWidth = LayoutStyle.sized(Integer.MAX_VALUE, 32);
public static LayoutStyle sized(int w, int h) {
LayoutStyle btn = new LayoutStyle();
btn.width = w;
btn.height = h;
return btn;
}
}

View File

@ -85,14 +85,6 @@ public class Box implements Serializable {
return new Box(x, y, x2 - x, y2 - y);
}
public static Box fromPoints(Vector2f a, Vector2i b) {
return new Box(a.x, a.y, b.x - a.x, b.y - a.y);
}
public static Box fromPoints(Vector2i a, Vector2f b) {
return new Box(a.x, a.y, b.x - a.x, b.y - a.y);
}
public Box copy() {
return new Box(x, y, w, h);
}
@ -100,56 +92,4 @@ public class Box implements Serializable {
public boolean contains(float x, float y) {
return x >= this.x && x < this.x2 && y >= this.y && y < this.y2;
}
public boolean contains(Vector2f pos) {
return contains(pos.x, pos.y);
}
public boolean intersects(Box other) {
boolean aLeftOfB = x2 <= other.x;
boolean aRightOfB = x >= other.x2;
boolean aAboveB = y >= other.y2;
boolean aBelowB = y2 <= other.y;
return !( aLeftOfB || aRightOfB || aAboveB || aBelowB );
}
public Vector2i[] getBorders() {
// TODO this could be bad, idk man. maybe define an intbox...
int x = (int) Math.round(this.x);
int y = (int) Math.round(this.y);
int w = (int) Math.round(this.w);
int h = (int) Math.round(this.h);
int size = 2 * w + 2 * h;
Vector2i[] vecs = new Vector2i[size];
// top / bottom row
for(int i = 0; i < h; i ++) {
vecs[i] = new Vector2i(x + i, y - 1);
vecs[size - i - 1] = new Vector2i(x + i, y + h);
}
// middle pillars
for(int i = 0; i < h; i ++) {
vecs[w + i * 2] = new Vector2i(x - 1, y + i);
vecs[w + i * 2 + 1] = new Vector2i(x + h, y + i);
}
return vecs;
}
public Box outset(float f) {
return new Box(x - f, y - f, w + 2 * f, h + 2 * f);
}
public Box quantize() {
return Box.fromPoints(
(float) Math.floor(x),
(float) Math.floor(y),
(float) Math.ceil(x2),
(float) Math.ceil(y2)
);
}
}

View File

@ -1,76 +0,0 @@
package xyz.valnet.engine.math;
import java.io.Serializable;
public class TileBox implements Serializable {
public final int x, y;
public final int w, h;
public final Vector2i topLeft;
@FunctionalInterface
public interface TileCallback {
public void apply(int x, int y);
}
public TileBox(int x, int y, int w, int h) {
if(w < 0) {
x += w + 1;
w *= -1;
}
if(h < 0) {
y += h + 1;
h *= -1;
}
this.x = x;
this.y = y;
this.w = w;
this.h = h;
topLeft = new Vector2i(x, y);
}
public TileBox(Vector2i pos, Vector2i dim) {
this(pos.x, pos.y, dim.x, dim.y);
}
public TileBox(int x, int y, Vector2i dim) {
this(x, y, dim.x, dim.y);
}
public TileBox(Vector2i pos, int w, int h) {
this(pos.x, pos.y, w, h);
}
public void forEach(TileCallback cb) {
for(int i = 0; i < w; i ++) {
for(int j = 0; j < h; j ++) {
cb.apply(x + i, y + j);
}
}
}
public static TileBox fromPoints(int x, int y, int x2, int y2) {
return new TileBox(
x <= x2 ? x : x2,
y <= y2 ? y : y2,
x <= x2 ? (x2 - x + 1) : (x - x2 + 1),
y <= y2 ? (y2 - y + 1) : (y - y2 + 1)
);
}
public static TileBox fromPoints(Vector2i a, int x2, int y2) {
return fromPoints(a.x, a.y, x2, y2);
}
public static TileBox fromPoints(int x, int y, Vector2i b) {
return fromPoints(x, y, b.x, b.y);
}
public static TileBox fromPoints(Vector2i a, Vector2i b) {
return fromPoints(a.x, a.y, b.x, b.y);
}
public Box asBox() {
return new Box(x, y, w, h);
}
}

View File

@ -23,7 +23,7 @@ public class Vector2f implements Serializable {
}
public Vector2i asInt() {
return new Vector2i((int)Math.floor(x), (int)Math.floor(y));
return new Vector2i((int)x, (int)y);
}
public boolean equals(Vector2f v) {
@ -51,10 +51,4 @@ public class Vector2f implements Serializable {
public String toString() {
return "<" + x + ", " + y + ">";
}
public Vector2f clamp(Box box) {
float x = Math.min(Math.max(this.x, box.x), box.x2);
float y = Math.min(Math.max(this.y, box.y), box.y2);
return new Vector2f(x, y);
}
}

View File

@ -6,9 +6,6 @@ public class Vector2i implements Serializable {
public int x, y;
public static Vector2i one = new Vector2i(1, 1);
public static Vector2i zero = new Vector2i(0, 0);
public Vector2i() {
x = 0;
y = 0;
@ -58,16 +55,8 @@ public class Vector2i implements Serializable {
return new Vector2i(x - 1, y);
}
public TileBox getTileBox() {
return new TileBox(x, y, 1, 1);
}
public String toString() {
return "<" + x + ", " + y + ">";
}
public Vector2i sub(Vector2i b) {
return new Vector2i(this.x - b.x, this.y - b.y);
public Box getTileBox() {
return new Box(x, y, 1, 1);
}
}

View File

@ -3,9 +3,6 @@ package xyz.valnet.engine.scenegraph;
import java.io.Serializable;
import java.util.List;
import xyz.valnet.engine.scenegraph.SceneGraph.GameObjectCallback;
import xyz.valnet.hadean.util.Pair;
public class GameObject implements IRenderable, ITickable, Serializable {
private transient SceneGraph scene;
@ -88,16 +85,4 @@ public class GameObject implements IRenderable, ITickable, Serializable {
protected boolean isPaused() {
return scene.isPaused();
}
protected Pair<Float, Integer> getFPS() {
return scene.getFPS();
}
protected void onAddGameObject(GameObjectCallback listener) {
scene.registerAddListener(listener);
}
protected void onRemoveGameObject(GameObjectCallback listener) {
scene.registerRemoveListener(listener);
}
}

View File

@ -1,7 +1,5 @@
package xyz.valnet.engine.scenegraph;
import xyz.valnet.engine.Game;
public interface IScene {
public void render();
public void update(float dTime);
@ -16,6 +14,6 @@ public interface IScene {
public void keyRelease(int key);
public void keyRepeat(int key);
public void enable(Game game);
public void enable();
public void disable();
}

View File

@ -4,7 +4,6 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
@ -16,10 +15,8 @@ import java.util.Set;
import java.util.stream.Collectors;
import xyz.valnet.engine.App;
import xyz.valnet.engine.Game;
import xyz.valnet.engine.math.Box;
import xyz.valnet.hadean.gameobjects.ui.tabs.DebugTab;
import xyz.valnet.hadean.util.Pair;
public abstract class SceneGraph implements IScene {
protected final List<GameObject> objects = new ArrayList<GameObject>();
@ -31,22 +28,6 @@ public abstract class SceneGraph implements IScene {
private boolean loadFlag = false;
private boolean saveFlag = false;
@FunctionalInterface
public interface GameObjectCallback extends Serializable {
public void apply(GameObject obj);
}
private Set<GameObjectCallback> onAddListeners = new HashSet<>();
private Set<GameObjectCallback> onRemoveListeners = new HashSet<>();
public void registerAddListener(GameObjectCallback cb) {
onAddListeners.add(cb);
}
public void registerRemoveListener(GameObjectCallback cb) {
onRemoveListeners.add(cb);
}
public <T> T get(Class<T> clazz) {
for(GameObject obj : objects) {
if(clazz.isInstance(obj)) {
@ -68,7 +49,6 @@ public abstract class SceneGraph implements IScene {
@Override
public void update(float dTime) {
dTime = Math.min(dTime, 6);
// ADD OBJECTS
if(!newObjects.isEmpty()) {
List<GameObject> added = new ArrayList<GameObject>();
@ -149,15 +129,13 @@ public abstract class SceneGraph implements IScene {
}
private boolean paused = false;
private Game game;
public boolean isPaused() {
return paused;
}
@Override
public void enable(Game game) {
this.game = game;
public void enable() {
this.construct();
for(GameObject obj : objects) {
@ -171,12 +149,6 @@ public abstract class SceneGraph implements IScene {
for(GameObject obj : objects) {
obj.addedToScene();
}
for(GameObject obj : objects) {
for(GameObjectCallback listener : onAddListeners) {
listener.apply(obj);
}
}
}
@Override
@ -202,9 +174,6 @@ public abstract class SceneGraph implements IScene {
newObjects.add(obj);
obj.link(this);
obj.addedToScene();
for(GameObjectCallback listener : onAddListeners) {
listener.apply(obj);
}
addObjectToCache(obj);
}
@ -216,9 +185,6 @@ public abstract class SceneGraph implements IScene {
public void remove(GameObject obj) {
removeObjects.add(obj);
for(GameObjectCallback listener : onRemoveListeners) {
listener.apply(obj);
}
}
public boolean inScene(GameObject gameObject) {
@ -249,12 +215,6 @@ public abstract class SceneGraph implements IScene {
.collect(Collectors.toList()));
}
private ArrayList<GameObject> getTransientObjects() {
return new ArrayList<GameObject>(objects.stream()
.filter(go -> (go instanceof ITransient))
.collect(Collectors.toList()));
}
private void save() {
try {
FileOutputStream file = new FileOutputStream("SAVE_DATA.TXT");
@ -282,7 +242,6 @@ public abstract class SceneGraph implements IScene {
input.close();
file.close();
DebugTab.log("imported " + newObjects.size() + " objects");
dump(newObjects);
ArrayList<GameObject> toRemove = getNonTransientObjects();
for(GameObject obj : toRemove) {
@ -294,12 +253,6 @@ public abstract class SceneGraph implements IScene {
for(GameObject obj : newObjects) obj.link(this);
for(GameObject obj : newObjects) obj.addedToScene();
// transients that survive a scene load, should be
// re-connected to the new scene
for(GameObject obj : getTransientObjects()) {
obj.connect();
}
} catch (Exception e) {
e.printStackTrace();
}
@ -369,8 +322,4 @@ public abstract class SceneGraph implements IScene {
iml.scrollUp();
}
}
public Pair<Float, Integer> getFPS() {
return new Pair<Float, Integer>(game.getAverageFPS(), game.getMeasuredFPS());
}
}

View File

@ -1,27 +0,0 @@
package xyz.valnet.engine.util;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class ClassToInstanceSet<B> {
private Map<Class<? extends B>, Set<B>> map = new HashMap<>();
private final <T extends B> void ensure(Class<T> clazz) {
if(!map.containsKey(clazz)) {
map.put(clazz, new HashSet<>());
}
}
public <T extends B> void add(Class<T> clazz, T obj) {
ensure(clazz);
var set = map.get(clazz);
set.add(obj);
}
@SuppressWarnings("unchecked") // it IS checked, by way of the add method.
public final <T extends B> Set<T> get(Class<T> clazz) {
return (Set<T>) map.get(clazz);
}
}

View File

@ -31,6 +31,14 @@ public class HadeanGame extends Game {
if(!debugView) return;
}
public float getAverageFPS() {
return averageFPS;
}
public int getMeasuredFPS() {
return measuredFPS;
}
// receive the updated matrix every frame for the actual window.
@Override
public void updateViewMatrix(Matrix4f matrix) {

View File

@ -0,0 +1,5 @@
package xyz.valnet.hadean;
public class ItemDescriptor {
}

View File

@ -1,7 +1,9 @@
package xyz.valnet.hadean.designation;
import xyz.valnet.hadean.gameobjects.worldobjects.Tree;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
@BuildableMetadata(category = "Jobs", name = "Chop Trees")
public class CutTreesDesignation extends Designation<Tree> {
@Override
@ -13,9 +15,4 @@ public class CutTreesDesignation extends Designation<Tree> {
protected void designate(Tree thing) {
thing.runAction(Tree.ACTION_CHOP);
}
@Override
public String getBuildTabName() {
return "ChopTrees";
}
}

View File

@ -2,10 +2,8 @@ package xyz.valnet.hadean.designation;
import java.util.List;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.BuildType;
import xyz.valnet.hadean.interfaces.IBuildable;
import xyz.valnet.hadean.interfaces.ISelectable;
@ -13,26 +11,39 @@ public abstract class Designation<T extends ISelectable> extends GameObject impl
@Override
@SuppressWarnings("unchecked")
public void buildAt(TileBox tileBox) {
Box box = tileBox.asBox();
public void buildAt(int x, int y, int w, int h) {
Class<T> type = getType();
List<T> things = getAll(type);
for(ISelectable thing : things) {
Box thingBox = thing.getWorldBox();
if(box.intersects(thingBox))
designate((T) thing);
Vector4f box = thing.getWorldBox();
if(rectanglesIntersect(x, y, x + w, y + h, box.x, box.y, box.z, box.w))
designate((T) thing);
}
}
@Override
public String getBuildTabCategory() {
return "Jobs";
@SuppressWarnings("unchecked")
public void buildAt(int x, int y) {
Class<T> type = getType();
List<T> things = getAll(type);
for(ISelectable thing : things) {
Vector4f box = thing.getWorldBox();
if(rectanglesIntersect(x, y, x + 1, y + 1, box.x, box.y, box.z, box.w))
designate((T) thing);
}
}
@Override
public BuildType getBuildType() {
return BuildType.AREA;
public boolean rectanglesIntersect(
float minAx, float minAy, float maxAx, float maxAy,
float minBx, float minBy, float maxBx, float maxBy ) {
boolean aLeftOfB = maxAx <= minBx;
boolean aRightOfB = minAx >= maxBx;
boolean aAboveB = minAy >= maxBy;
boolean aBelowB = maxAy <= minBy;
return !( aLeftOfB || aRightOfB || aAboveB || aBelowB );
}
protected abstract Class<T> getType();
protected abstract void designate(T thing);

View File

@ -1,9 +1,12 @@
package xyz.valnet.hadean.designation;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
@BuildableMetadata(category = "Jobs", name = "Haul Items")
public class HaulItemDesignation extends Designation<Item> {
@Override
protected Class<Item> getType() {
return Item.class;
@ -13,9 +16,4 @@ public class HaulItemDesignation extends Designation<Item> {
protected void designate(Item thing) {
thing.runAction(Item.HAUL);
}
@Override
public String getBuildTabName() {
return "Haul Items";
}
}

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.ui;
package xyz.valnet.hadean.gameobjects;
import java.util.ArrayList;
import java.util.HashMap;

View File

@ -8,7 +8,6 @@ import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.graphics.Tile9;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
@ -32,8 +31,6 @@ public class Camera extends GameObject implements ITransient, IMouseCaptureArea
private float minY, maxY;
private Box focusBounds = null;
@Override
public void start() {
IWorldBoundsAdapter worldBoundsAdapter = get(IWorldBoundsAdapter.class);
@ -42,11 +39,7 @@ public class Camera extends GameObject implements ITransient, IMouseCaptureArea
maxY = bounds.w;
}
public final void setFocusBounds(Box box) {
this.focusBounds = box;
}
public final Vector2f getWorldMouse() {
public Vector2f getWorldMouse() {
return screen2world(App.mouseX, App.mouseY);
}
@ -74,10 +67,6 @@ public class Camera extends GameObject implements ITransient, IMouseCaptureArea
Vector2f dragDifference = screen2world(App.mouseX, App.mouseY).subtract(focus);
focus = dragOrigin.subtract(dragDifference);
}
if(focusBounds != null) {
focus = focus.clamp(focusBounds);
}
}
public void focus(float x, float y) {
@ -85,32 +74,24 @@ public class Camera extends GameObject implements ITransient, IMouseCaptureArea
this.focus.y = y;
}
public final Box world2screen(Box box) {
return Box.fromPoints(world2screen(box.a), world2screen(box.b));
}
public final Vector2i world2screen(float x, float y) {
public Vector2i world2screen(float x, float y) {
return new Vector2i((int)(x * tileWidth + screenWidth / 2 - focus.x * tileWidth), (int)(y * tileWidth + screenHeight / 2 - focus.y * tileWidth));
}
public final Vector2i world2screen(Vector2f pos) {
public Vector2i world2screen(Vector2f pos) {
return world2screen(pos.x, pos.y);
}
public final Vector2i world2screen(Vector2i pos) {
return world2screen(pos.x, pos.y);
}
public final Vector2f screen2world(float x, float y) {
public Vector2f screen2world(float x, float y) {
return new Vector2f((x - screenWidth / 2 + focus.x * tileWidth) / tileWidth, (y - screenHeight / 2 + focus.y * tileWidth) / tileWidth);
}
public final Vector2f screen2world(Vector2f pos) {
public Vector2f screen2world(Vector2f pos) {
return screen2world(pos.x, pos.y);
}
// !! this takes an AABB and returns and AABB
public final Vector4f world2screen(Vector4f input) {
public Vector4f world2screen(Vector4f input) {
return new Vector4f(
input.x * tileWidth + screenWidth / 2 - focus.x * tileWidth,
input.y * tileWidth + screenHeight / 2 - focus.y * tileWidth,
@ -120,58 +101,53 @@ public class Camera extends GameObject implements ITransient, IMouseCaptureArea
}
@Deprecated
public final void draw(Sprite sprite, float x, float y) {
public void draw(Sprite sprite, float x, float y) {
Vector2i screenPos = world2screen(x, y);
Drawing.drawSprite(sprite, (screenPos.x), (screenPos.y), tileWidth, tileWidth);
}
@Deprecated
public final void draw(Sprite sprite, float x, float y, float w, float h) {
public void draw(Sprite sprite, float x, float y, float w, float h) {
Vector2i screenPos = world2screen(x, y);
Drawing.drawSprite(sprite, (screenPos.x), (screenPos.y), (int)(tileWidth * w), (int)(tileWidth * h));
}
public final void draw(float layer, Sprite sprite, float x, float y) {
public void draw(float layer, Sprite sprite, float x, float y) {
draw(layer, sprite, x, y, 1, 1);
}
public final void draw(float layer, Sprite sprite, Vector2f pos) {
public void draw(float layer, Sprite sprite, Vector2f pos) {
draw(layer, sprite, pos.x, pos.y, 1, 1);
}
public final void draw(float layer, Sprite sprite, Vector4i pos) {
public void draw(float layer, Sprite sprite, Vector4i pos) {
draw(layer, sprite, pos.x, pos.y, pos.z, pos.w);
}
public final void draw(float layer, Sprite sprite, float x, float y, float w, float h) {
public void draw(float layer, Sprite sprite, float x, float y, float w, float h) {
Vector2i screenPos = world2screen(x, y);
Drawing.setLayer(layer + (((y + h) - minY) / (maxY - minY)));
Drawing.drawSprite(sprite, (int)(screenPos.x), (int)(screenPos.y), (int)(tileWidth * w), (int)(tileWidth * h));
}
@Deprecated
public final void draw(float layer, Tile9 sprite, Box box) {
public void draw(float layer, Tile9 sprite, Box box) {
draw(layer, sprite, box.x, box.y, box.w, box.h);
}
public final void draw(float layer, Tile9 sprite, TileBox box) {
draw(layer, sprite, box.x, box.y, box.w, box.h);
}
public final void draw(float layer, Tile9 sprite, float x, float y, float w, float h) {
public void draw(float layer, Tile9 sprite, float x, float y, float w, float h) {
Vector2i screenPos = world2screen(x, y);
Drawing.setLayer(layer + (((y + h) - minY) / (maxY - minY)));
sprite.draw((int)(screenPos.x), (int)(screenPos.y), (int)(tileWidth * w), (int)(tileWidth * h));
}
public final void drawProgressBar(float progress, Box worldBox) {
public void drawProgressBar(float progress, Vector4f worldBox) {
int h = 6;
Box box = world2screen(worldBox);
Vector4i box = world2screen(worldBox).toXYWH().asInt();
Drawing.setLayer(Layers.GENERAL_UI);
Assets.flat.pushColor(Color.black);
Assets.uiFrame.draw((int)(box.x - h), (int)(box.y + box.h / 2 - h / 2), (int)(box.w + h * 2), h);
Assets.uiFrame.draw(box.x - h, box.y + box.w / 2 - h / 2, box.z + h * 2, h);
Assets.flat.swapColor(Color.yellow);
Assets.fillColor.draw((int)(box.x + 1 - h), (int)(box.y + 1 + box.h / 2 - h / 2), (int)Math.round(lerp(0, box.w - 3 + h * 2, progress)) + 1, h - 2);
Assets.fillColor.draw(box.x + 1 - h, box.y + 1 + box.w / 2 - h / 2, (int)Math.round(lerp(0, box.z - 3 + h * 2, progress)) + 1, h - 2);
Assets.flat.popColor();
}

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.jobs;
package xyz.valnet.hadean.gameobjects;
import java.io.Serializable;
import java.util.ArrayList;
@ -8,8 +8,8 @@ import java.util.Set;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.worldobjects.Stockpile;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.gameobjects.worldobjects.zones.Stockpile;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.IItemReceiver;
import xyz.valnet.hadean.interfaces.IWorkable;
@ -120,15 +120,11 @@ public class Job extends GameObject {
}
public Vector2i[] getLocations() {
List<Stockpile> stockpiles = that.getAll(Stockpile.class);
for(Stockpile pile : stockpiles) {
Vector2i tile = pile.getFreeTile();
if(tile == null) continue;
return new Vector2i[] {
tile
};
}
return new Vector2i[] {};
Stockpile pile = that.get(Stockpile.class);
// Vector4f box = pile.getWorldBox().toXYWH();
return new Vector2i[] {
pile.getFreeTile()
};
}
@Override

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.jobs;
package xyz.valnet.hadean.gameobjects;
import java.util.ArrayList;
import java.util.HashMap;
@ -13,8 +13,7 @@ import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.HadeanGame;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn.Pawn;
import xyz.valnet.hadean.gameobjects.worldobjects.pawn.Pawn;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.IItemReceiver;
import xyz.valnet.hadean.interfaces.IWorkable;
@ -28,8 +27,8 @@ public class JobBoard extends GameObject {
private List<Job> toRemove = new ArrayList<Job>();
private Map<Pawn, Job> allocations = new HashMap<Pawn, Job>();
public Job postSimpleWorkJob(IWorkable subject) {
Job job = add(new Job(subject.getJobName()));
public Job postSimpleWorkJob(String name, IWorkable subject) {
Job job = add(new Job(name));
job.addStep(job.new Work(subject));
postJob(job);
return job;
@ -208,7 +207,6 @@ public class JobBoard extends GameObject {
return str;
}
@Deprecated
public String details() {
String takenJobsString = "";
@ -236,4 +234,5 @@ public class JobBoard extends GameObject {
"Taken Jobs: " + allocations.size() + "\n" + takenJobsString +
"Impossible Jobs: " + impossibleJobs + "\n" + impossibleJobsString;
}
}

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.ui;
package xyz.valnet.hadean.gameobjects;
import static xyz.valnet.engine.util.Math.*;
@ -13,6 +13,7 @@ import xyz.valnet.engine.graphics.ImmediateUI;
import xyz.valnet.engine.scenegraph.ITransient;
import xyz.valnet.hadean.Constants;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.ui.ExclusivityManager;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ISelectionChangeListener;
import xyz.valnet.hadean.util.Action;
@ -132,7 +133,7 @@ public class SelectionUI extends ImmediateUI implements ISelectionChangeListener
if(details.length == 0) {
text("No details available.");
} else for(Detail detail : details) {
text(detail.toString(30));
text(detail.toString(15));
}
});
} else {

View File

@ -1,11 +1,9 @@
package xyz.valnet.hadean.gameobjects.terrain;
package xyz.valnet.hadean.gameobjects;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.FastNoiseLite;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.interfaces.IWorldBoundsAdapter;
import xyz.valnet.hadean.pathfinding.IPathable;
@ -44,7 +42,6 @@ public class Terrain extends GameObject implements IPathable, IWorldBoundsAdapte
@Override
protected void start() {
camera.focus(WORLD_SIZE / 2, WORLD_SIZE / 2);
camera.setFocusBounds(new Box(0, 0, WORLD_SIZE, WORLD_SIZE));
}
public Tile getTile(int x, int y) {

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.terrain;
package xyz.valnet.hadean.gameobjects;
import java.util.ArrayList;
import java.util.HashSet;
@ -9,12 +9,11 @@ import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.worldobjects.FarmPlot;
import xyz.valnet.hadean.gameobjects.worldobjects.Tree;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Boulder;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.gameobjects.worldobjects.zones.FarmPlot;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.IPingable;
import xyz.valnet.hadean.interfaces.ITileThing;
@ -124,7 +123,7 @@ public class Tile extends WorldObject implements IWorkable {
pingNeighbors();
if(thing instanceof FarmPlot) {
get(JobBoard.class).postSimpleWorkJob(this);
get(JobBoard.class).postSimpleWorkJob("Till Soil", this);
}
}

View File

@ -4,13 +4,12 @@ import java.util.List;
import xyz.valnet.engine.App;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.IMouseCaptureArea;
import xyz.valnet.engine.scenegraph.ITransient;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.interfaces.BuildType;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.interfaces.IBuildLayerListener;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
@ -25,9 +24,9 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
private IBuildLayerListener listener = null;
private BuildType type = BuildType.AREA;
private BuildableMetadata.Type type = BuildableMetadata.Type.AREA;
public void setBuildType(BuildType type) {
public void setBuildType(BuildableMetadata.Type type) {
this.type = type;
}
@ -39,7 +38,7 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
@Override
public void update(float dTime) {
if(listener == null) return;
if(type == BuildType.SINGLE && mouseDown) return;
if(type == BuildableMetadata.Type.SINGLE && mouseDown) return;
broadcastWorldCoords();
}
@ -59,16 +58,13 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
}
private void broadcastWorldCoords() {
Vector2i worldcoords = camera.getWorldMouse().asInt();
Vector2i worldcoords = camera.screen2world(App.mouseX, App.mouseY).asInt();
if(mouseDown) {
listener.update(TileBox.fromPoints(startingPoint, camera.getWorldMouse().asInt()));
Vector2i[] ords = orderCoords(new Vector2i(x, y), worldcoords);
listener.update(ords[0].x, ords[0].y, ords[2].x + 1, ords[2].y + 1);
return;
}
if(type == BuildType.SINGLE && dimensions != null) {
listener.update(new TileBox(worldcoords, dimensions));
} else {
listener.update(new TileBox(worldcoords, Vector2i.one));
}
listener.update(worldcoords.x, worldcoords.y, 1, 1);
}
public void deactiveate() {
@ -86,15 +82,9 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
hovered = false;
}
private Vector2i startingPoint = null;
private int x, y;
private boolean mouseDown = false;
private Vector2i dimensions = new Vector2i(1, 1);
public void setDimensions(Vector2i dimensions) {
this.dimensions = dimensions;
}
@Override
public void mouseDown(int button) {
if(button == 1 && active && hovered) {
@ -102,10 +92,12 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
listener.cancel();
} else if(button == 0 && active && hovered) {
// TODO this conversion in negative numbers definitely works wrong.
startingPoint = camera.getWorldMouse().asInt();
Vector2i worldcoords = camera.screen2world(App.mouseX, App.mouseY).asInt();
mouseDown = true;
if(type == BuildType.SINGLE) {
listener.build(new TileBox(startingPoint, dimensions));
x = worldcoords.x;
y = worldcoords.y;
if(type == BuildableMetadata.Type.SINGLE) {
listener.build(x, y);
}
}
}
@ -114,12 +106,29 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea, ITransi
public void mouseUp(int button) {
if(button == 0 && active && mouseDown) {
mouseDown = false;
if(type == BuildType.AREA) {
listener.build(TileBox.fromPoints(camera.getWorldMouse().asInt(), startingPoint));
if(type == BuildableMetadata.Type.AREA) {
Vector2i worldcoords = camera.screen2world(App.mouseX, App.mouseY).asInt();
int x1 = x;
int y1 = y;
int x2 = worldcoords.x;
int y2 = worldcoords.y;
int minX = Math.min(x1, x2);
int minY = Math.min(y1, y2);
int maxX = Math.max(x1, x2);
int maxY = Math.max(y1, y2);
listener.build(minX, minY, maxX, maxY);
}
}
}
private Vector2i[] orderCoords(Vector2i a, Vector2i b) {
return new Vector2i[] {
new Vector2i(Math.min(a.x, b.x), Math.min(a.y, b.y)),
new Vector2i(Math.max(a.x, b.x), Math.max(a.y, b.y)),
new Vector2i(Math.max(a.x, b.x) - Math.min(a.x, b.x), Math.max(a.y, b.y) - Math.min(a.y, b.y))
};
}
@Override
public List<Box> getGuiBoxes() {
return List.of(active ? new Box(0, 0, 1024, 576) : Box.none);

View File

@ -9,6 +9,8 @@ import xyz.valnet.engine.App;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.IMouseCaptureArea;
import xyz.valnet.engine.scenegraph.ITransient;
@ -78,8 +80,11 @@ public class SelectionLayer extends GameObject implements IMouseCaptureArea, ITr
float p = lerp(animationAmplitude, 0, t);
for(ISelectable thing : selected) {
Box box = thing.getWorldBox().outset(p);
camera.draw(Layers.SELECTION_IDENTIFIERS, Assets.selectedFrame, box);
Vector4f box = thing.getWorldBox();
Vector2i min = camera.world2screen(box.x - p, box.y - p);
Vector2i max = camera.world2screen(box.z + p, box.w + p);
Drawing.setLayer(Layers.SELECTION_IDENTIFIERS);
Assets.selectedFrame.draw((int)min.x, (int)min.y, (int)(max.x - min.x), (int)(max.y - min.y));
thing.selectedRender();
}
@ -91,17 +96,37 @@ public class SelectionLayer extends GameObject implements IMouseCaptureArea, ITr
}
}
// this will take any x1, y1, x2, y2 vector and make x1 < x2 and y1 < y2;
private Vector4f sortVector(Vector4f vector) {
return new Vector4f(
Math.min(vector.x, vector.z),
Math.min(vector.y, vector.w),
Math.max(vector.x, vector.z),
Math.max(vector.y, vector.w)
);
}
private List<ISelectable> selected = new ArrayList<ISelectable>();
private void makeSelection(Box selectionBox) {
private void makeSelection(Vector4f a) {
List<ISelectable> newSelection = new ArrayList<ISelectable>();
Vector4f normalizedSelectionBoxScreen = sortVector(a);
Vector2f selectionBoxWorldMin = new Vector2f(normalizedSelectionBoxScreen.x, normalizedSelectionBoxScreen.y);
Vector2f selectionBoxWorldMax = new Vector2f(normalizedSelectionBoxScreen.z, normalizedSelectionBoxScreen.w);
List<ISelectable> selectables = getAll(ISelectable.class);
int prio = Integer.MIN_VALUE;
for(ISelectable thing : selectables) {
Box thingBox = thing.getWorldBox();
if(selectionBox.intersects(thingBox)) {
Vector4f thingBox = thing.getWorldBox();
if(rectanglesIntersect(
selectionBoxWorldMin.x, selectionBoxWorldMin.y,
selectionBoxWorldMax.x, selectionBoxWorldMax.y,
thingBox.x, thingBox.y,
thingBox.z, thingBox.w
)) {
int thingPrio = thing.getSelectPriority().toValue();
if(thingPrio > prio) {
newSelection.clear();
@ -191,7 +216,18 @@ public class SelectionLayer extends GameObject implements IMouseCaptureArea, ITr
@Override
public void mouseUp(int button) {
if(initialCoords != null && button == 0) {
makeSelection(Box.fromPoints(initialCoords, camera.getWorldMouse()));
Vector2f worldMouse = camera.screen2world(App.mouseX, App.mouseY);
Vector4f worldBox = new Vector4f(
initialCoords.x,
initialCoords.y,
worldMouse.x,
worldMouse.y
);
makeSelection(worldBox);
initialCoords = null;
}
}

View File

@ -1,50 +0,0 @@
package xyz.valnet.hadean.gameobjects.jobs;
import java.io.Serializable;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.interfaces.IWorkable;
public class SimpleWorkable implements IWorkable {
private final String name;
private float work = 0;
private float MAX_WORK = 0;
private IProgressUpdateCallback callback;
private IGetPositionsFunction positions;
@FunctionalInterface
public interface IGetPositionsFunction extends Serializable {
public Vector2i[] get();
}
@FunctionalInterface
public interface IProgressUpdateCallback extends Serializable {
public void progress(float progress);
}
public SimpleWorkable(String name, float maxWork, IGetPositionsFunction positionsFunction, IProgressUpdateCallback callback) {
this.name = name;
this.MAX_WORK = maxWork;
this.positions = positionsFunction;
this.callback = callback;
}
@Override
public boolean doWork(float dTime) {
work += dTime;
callback.progress(work / MAX_WORK);
return work >= MAX_WORK;
}
@Override
public Vector2i[] getWorkablePositions() {
return positions.get();
}
@Override
public final String getJobName() {
return name;
}
}

View File

@ -1,45 +0,0 @@
package xyz.valnet.hadean.gameobjects.jobs;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.IWorkshop;
public class WorkOrder extends GameObject {
private boolean recurring = false;
private int count = 10;
private String name = "Cut Stone Blocks";
private IWorkshop shop = null;
public boolean getRecurring() {
return recurring;
}
public int getCount() {
return count;
}
public String getName() {
return name;
}
public void increaseCount() {
count ++;
}
public void decreaseCount() {
count --;
}
public WorkOrder setShop(IWorkshop shop) {
this.shop = shop;
return this;
}
public boolean validForShop(IWorkshop shop) {
return this.shop == null || this.shop == shop;
}
public boolean isSpecificToShop(IWorkshop shop) {
return this.shop != null && shop == this.shop;
}
}

View File

@ -1,41 +0,0 @@
package xyz.valnet.hadean.gameobjects.jobs;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.IWorkshop;
public class WorkOrderManager extends GameObject {
private Set<WorkOrder> orders;
@Override
protected void start() {
super.start();
this.onAddGameObject((obj) -> {
if(obj instanceof WorkOrder) {
orders.add((WorkOrder) obj);
}
});
this.onRemoveGameObject((obj) -> {
if(obj instanceof WorkOrder) {
orders.remove((WorkOrder) obj);
}
});
}
@Override
protected void create() {
super.create();
orders = new HashSet<>();
}
public Set<WorkOrder> getOrders(IWorkshop shop) {
return orders.stream()
.filter((order) -> order.validForShop(shop))
.collect(Collectors.toSet());
}
}

View File

@ -5,13 +5,14 @@ import java.util.List;
import xyz.valnet.engine.App;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.ITransient;
import xyz.valnet.hadean.HadeanGame;
import xyz.valnet.hadean.gameobjects.BottomBar;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.util.Assets;
@ -42,8 +43,13 @@ public class HoverQuery extends GameObject implements ITransient {
Vector2f position = camera.screen2world(App.mouseX, App.mouseY);
thingStrings.clear();
for(WorldObject obj : getAll(WorldObject.class)) {
Box box = obj.getWorldBox();
if(box.contains(position)) {
Vector4f box = obj.getWorldBox();
if(
position.x >= box.x &&
position.x < box.z &&
position.y >= box.y &&
position.y < box.w
) {
thingStrings.add(obj.getName());
if (!HadeanGame.debugView) continue;

View File

@ -1,95 +0,0 @@
package xyz.valnet.hadean.gameobjects.ui;
import xyz.valnet.engine.graphics.LayoutStyle;
import xyz.valnet.engine.graphics.ImmediateUI;
import xyz.valnet.engine.scenegraph.ITransient;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.jobs.WorkOrder;
import xyz.valnet.hadean.gameobjects.jobs.WorkOrderManager;
import xyz.valnet.hadean.interfaces.IWorkshop;
public class WorkshopOrdersUI extends ImmediateUI implements ITransient {
private IWorkshop shop;
private SelectionLayer selectionLayer;
private WorkOrderManager manager;
public void open(IWorkshop shop) {
this.shop = shop;
}
public void close() {
this.shop = null;
}
@Override
protected void gui() {
if(shop == null) return;
window(0, 0, 200, 300, () -> {
var all = manager.getOrders(shop);
var specifics = all.stream()
.filter(workorder -> workorder.isSpecificToShop(shop))
.toList();
for(WorkOrder order : specifics) {
group(() -> {
text(order.getName());
space(4);
horizontal(() -> {
if(button("--", LayoutStyle.sized(32, 16))) {
order.decreaseCount();
}
space(4);
if(button("-", LayoutStyle.sized(16, 16))) {
order.decreaseCount();
}
space(4);
vertical(() -> {
// space(8);
text("" + order.getCount());
});
space(4);
if(button("+", LayoutStyle.sized(16, 16))) {
order.increaseCount();
}
space(4);
if(button("++", LayoutStyle.sized(32, 16))) {
order.increaseCount();
}
});
});
space(8);
}
text("" + (all.size() - specifics.size()) + " implicit general orders");
space(8);
if(button("New Order")) {
add(new WorkOrder().setShop(shop));
}
});
}
@Override
protected void connect() {
super.connect();
selectionLayer = get(SelectionLayer.class);
manager = get(WorkOrderManager.class);
}
@Override
protected void start() {
super.start();
this.selectionLayer.subscribe((selection) -> {
if(shop == null) {
return;
} else if(selection.size() != 1) {
close();
} else if(selection.get(0) instanceof IWorkshop) {
shop = (IWorkshop) selection.get(0);
}
});
}
}

View File

@ -8,22 +8,20 @@ import java.util.Map;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.designation.CutTreesDesignation;
import xyz.valnet.hadean.designation.HaulItemDesignation;
import xyz.valnet.hadean.gameobjects.ui.BottomBar;
import xyz.valnet.hadean.gameobjects.BottomBar;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.inputlayer.BuildLayer;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.worldobjects.zones.FarmPlot;
import xyz.valnet.hadean.gameobjects.worldobjects.zones.Stockpile;
import xyz.valnet.hadean.gameobjects.worldobjects.FarmPlot;
import xyz.valnet.hadean.gameobjects.worldobjects.Stockpile;
import xyz.valnet.hadean.gameobjects.worldobjects.constructions.Bed;
import xyz.valnet.hadean.gameobjects.worldobjects.constructions.MasonWorkshop;
import xyz.valnet.hadean.gameobjects.worldobjects.constructions.Quarry;
import xyz.valnet.hadean.gameobjects.worldobjects.constructions.Wall;
import xyz.valnet.hadean.interfaces.BuildType;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.interfaces.IBuildLayerListener;
import xyz.valnet.hadean.interfaces.IBuildable;
import xyz.valnet.hadean.interfaces.ISelectable;
@ -37,7 +35,8 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
private BuildLayer buildLayer;
private Camera camera;
private TileBox renderBox = null;
private int x, y;
private int w, h;
private String selectedCategory = null;
@ -56,23 +55,21 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
BuildTab.registerBuildable(FarmPlot.class);
BuildTab.registerBuildable(Stockpile.class);
BuildTab.registerBuildable(MasonWorkshop.class);
}
public record BuildableRecord(
String name,
Constructor<? extends IBuildable> constructor,
BuildType type,
Vector2i dimensions
BuildableMetadata.Type type
) {}
public static void registerBuildable(Class<? extends IBuildable> clazz) {
try {
// BuildableMetadata annotation = clazz.getAnnotation(BuildableMetadata.class);
// if(annotation == null) {
// DebugTab.log(clazz + " has no buildable data annotation");
// return;
// }
BuildableMetadata annotation = clazz.getAnnotation(BuildableMetadata.class);
if(annotation == null) {
DebugTab.log(clazz + " has no buildable data annotation");
return;
}
Constructor<? extends IBuildable> constructor = (Constructor<? extends IBuildable>) clazz.getConstructor();
if(constructor.getParameterCount() != 0) {
@ -80,18 +77,15 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
return;
}
IBuildable buildable = constructor.newInstance();
String category = buildable.getBuildTabCategory();
String name = buildable.getBuildTabName();
BuildType type = buildable.getBuildType();
Vector2i dim = buildable.getDimensions();
String category = annotation.category();
String name = annotation.name();
BuildableMetadata.Type type = annotation.type();
DebugTab.log("Added " + category + " / " + name);
if(!buildables.containsKey(category))
buildables.put(category, new ArrayList<BuildableRecord>());
buildables.get(category).add(new BuildableRecord(name, constructor, type, dim));
buildables.get(category).add(new BuildableRecord(name, constructor, type));
} catch (Exception e) {
e.printStackTrace();
@ -104,19 +98,15 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
if(!opened || selectedBuildable == null) return;
// draw the currently selected build item
Assets.flat.pushColor(Color.white);
Vector2i topLeft = camera.world2screen(renderBox.topLeft);
Vector2i topLeft = camera.world2screen(x, y);
Assets.font.drawString(selectedBuildable.name, topLeft.x, topLeft.y - 20);
Assets.flat.swapColor(Color.white.withAlpha(0.6f));
camera.draw(Layers.BUILD_INTERACTABLE, Assets.selectionFrame, renderBox);
camera.draw(Layers.BUILD_INTERACTABLE, Assets.selectionFrame, x, y, w, h);
Assets.flat.swapColor(Color.white.withAlpha(0.35f));
for(int i = 0; i < renderBox.w; i ++) for(int j = 0; j < renderBox.h; j ++) {{
camera.draw(Layers.BUILD_INTERACTABLE, Assets.checkerBoard, renderBox.x + i, renderBox.y + j);
for(int i = 0; i < w; i ++) for(int j = 0; j < h; j ++) {{
camera.draw(Layers.BUILD_INTERACTABLE, Assets.checkerBoard, x + i, y + j);
}}
Assets.flat.popColor();
}
@ -154,7 +144,42 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
selectedBuildable = buildableRecord;
buildLayer.activate(this);
buildLayer.setBuildType(selectedBuildable.type);
buildLayer.setDimensions(selectedBuildable.dimensions);
}
@Override
public void update(int nx, int ny, int nw, int nh) {
x = nx;
y = ny;
w = nw;
h = nh;
}
@Override
public void build(int x1, int y1, int x2, int y2) {
if(selectedBuildable == null) return;
try {
IBuildable building = selectedBuildable.constructor.newInstance();
if(building instanceof GameObject) {
add((GameObject) building);
}
building.buildAt(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
} catch (Exception e) {
DebugTab.log(e);
}
}
@Override
public void build(int x1, int y1) {
if(selectedBuildable == null) return;
try {
IBuildable building = selectedBuildable.constructor.newInstance();
if(building instanceof GameObject) {
add((GameObject) building);
}
building.buildAt(x1, y1);
} catch (Exception e) {
DebugTab.log(e);
}
}
@Override
@ -234,23 +259,4 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IBuildLay
protected void onOpen() {
reset();
}
@Override
public void update(TileBox box) {
renderBox = box;
}
@Override
public void build(TileBox box) {
if(selectedBuildable == null) return;
try {
IBuildable building = selectedBuildable.constructor.newInstance();
if(building instanceof GameObject) {
add((GameObject) building);
}
building.buildAt(box);
} catch (Exception e) {
DebugTab.log(e);
}
}
}

View File

@ -5,7 +5,7 @@ import java.util.List;
import xyz.valnet.engine.scenegraph.IKeyboardListener;
import xyz.valnet.hadean.HadeanGame;
import xyz.valnet.hadean.gameobjects.ui.BottomBar;
import xyz.valnet.hadean.gameobjects.BottomBar;
public class DebugTab extends Tab implements IKeyboardListener {
@ -44,10 +44,6 @@ public class DebugTab extends Tab implements IKeyboardListener {
space(8);
text(System.getProperty("java.version"));
space(8);
var fps = getFPS();
text("FPS: " + fps.first());
text("MEASURED FPS: " + fps.second());
space(8);
long allocated = runtime.totalMemory();
long max = runtime.maxMemory();
@ -69,7 +65,6 @@ public class DebugTab extends Tab implements IKeyboardListener {
while(logs.size() > 10) {
logs.remove(0);
}
System.out.println(str);
}
public static void log(Object obj) {

View File

@ -1,7 +1,7 @@
package xyz.valnet.hadean.gameobjects.ui.tabs;
import xyz.valnet.hadean.gameobjects.ui.BottomBar;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.BottomBar;
import xyz.valnet.hadean.gameobjects.JobBoard;
public class JobBoardTab extends Tab {

View File

@ -19,8 +19,6 @@ public class MenuTab extends Tab implements IPauser {
@Override
protected void gui() {
if(!shouldRender()) return;
window(1024 / 2 - width / 2, animate(-height - 50, 576 / 2 - height / 2), width, height, () -> {
text(" === Paused ===");
space(8);

View File

@ -6,7 +6,7 @@ import xyz.valnet.engine.graphics.IModalUI;
import xyz.valnet.engine.graphics.ImmediateUI;
import xyz.valnet.engine.scenegraph.ITransient;
import xyz.valnet.hadean.Constants;
import xyz.valnet.hadean.gameobjects.ui.BottomBar;
import xyz.valnet.hadean.gameobjects.BottomBar;
import xyz.valnet.hadean.gameobjects.ui.ExclusivityManager;
import xyz.valnet.hadean.interfaces.IBottomBarItem;
import xyz.valnet.hadean.util.Layers;

View File

@ -1,7 +1,7 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.interfaces.IBuildable;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ITileThing;
@ -10,9 +10,19 @@ import xyz.valnet.hadean.util.detail.Detail;
public abstract class Buildable extends WorldObject implements IBuildable, ITileThing, ISelectable {
protected Vector2i getDimensions() {
return new Vector2i(1, 1);
}
@Override
public void buildAt(TileBox box) {
setPosition(box.asBox());
public void buildAt(int x, int y, int w, int h) {
setPosition(x, y, w, h);
}
@Override
public void buildAt(int x, int y) {
Vector2i dim = getDimensions();
setPosition(x, y, dim.x, dim.y);
}
@Override
@ -20,6 +30,7 @@ public abstract class Buildable extends WorldObject implements IBuildable, ITile
@Override
public Action[] getActions() {
// TODO Auto-generated method stub
return new Action[] {};
}
@ -32,9 +43,4 @@ public abstract class Buildable extends WorldObject implements IBuildable, ITile
public Detail[] getDetails() {
return new Detail[] {};
}
@Override
public String getBuildTabName() {
return getName();
}
}

View File

@ -1,22 +1,23 @@
package xyz.valnet.hadean.gameobjects.worldobjects.zones;
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector4i;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
import xyz.valnet.hadean.util.detail.Detail;
public class FarmPlot extends Zone {
@BuildableMetadata(category = "Zones", name = "Farm Plot")
public class FarmPlot extends Buildable {
@Override
public void renderAlpha() {
if(!visible) return;
Vector4i pos = getWorldPosition();
Assets.flat.pushColor(new Color(0.4f, 1f, 0.3f, 0.2f));
camera.draw(Layers.TILES, Assets.whiteBox, pos.x, pos.y, pos.z, pos.w);
camera.draw(Layers.GROUND, Assets.whiteBox, pos.x, pos.y, pos.z, pos.w);
Assets.flat.popColor();
}
@ -64,8 +65,4 @@ public class FarmPlot extends Zone {
@Override
public void onPlaced(Tile tile) {}
@Override
public ISelectable.Priority getSelectPriority() {
return ISelectable.Priority.LOW;
}
}

View File

@ -0,0 +1,61 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
import xyz.valnet.hadean.util.detail.Detail;
public class Rice extends Item {
public Rice(int x, int y) {
setPosition(x, y);
}
@Override
public void render() {
Vector2i pos = getWorldPosition().xy();
camera.draw(Layers.AIR, Assets.riceBag, pos.x, pos.y);
Assets.flat.pushColor(Color.black);
Vector2i screeCoords = camera.world2screen(pos.x, pos.y);
Assets.miniFont.drawString("123", (int)screeCoords.x, (int)screeCoords.y);
Assets.flat.popColor();
}
@Override
public boolean isWalkable() {
return true;
}
@Override
public boolean shouldRemove() {
return false;
}
@Override
public void onRemove() {}
@Override
public Action[] getActions() {
return new Action[] {};
}
@Override
public void runAction(Action action) {
}
@Override
public Detail[] getDetails() {
return new Detail[] {};
}
@Override
public String getName() {
return "Rice";
}
}

View File

@ -1,18 +1,20 @@
package xyz.valnet.hadean.gameobjects.worldobjects.zones;
package xyz.valnet.hadean.gameobjects.worldobjects;
import java.util.Set;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4i;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
import xyz.valnet.hadean.util.detail.Detail;
public class Stockpile extends Zone {
@BuildableMetadata(category = "Zones", name = "Stockpile")
public class Stockpile extends Buildable {
@Override
public void render() {

View File

@ -1,10 +1,10 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.jobs.Job;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Log;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ITileThing;
@ -18,6 +18,9 @@ import xyz.valnet.hadean.util.detail.PercentDetail;
public class Tree extends WorldObject implements ITileThing, ISelectable, IWorkable {
private static int counter = 0;
private String name = "Tree " + (++ counter);
private Job chopJob = null;
public Tree(int x, int y) {
@ -32,7 +35,7 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
// Assets.flat.popColor();
if(chopJob != null) {
if(getProgress() > 0) {
camera.drawProgressBar(getProgress(), new Box(pos.x - 1, pos.y - 2, 3, 3));
camera.drawProgressBar(getProgress(), new Vector4f(pos.x - 1, pos.y - 2, pos.x + 2, pos.y + 1));
}
camera.draw(Layers.MARKERS, Assets.lilAxe, pos.x, pos.y);
}
@ -56,7 +59,7 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
public void runAction(Action action) {
if(action == ACTION_CHOP) {
if(chopJob == null) {
chopJob = get(JobBoard.class).postSimpleWorkJob(this);
chopJob = get(JobBoard.class).postSimpleWorkJob("Chop Tree", this);
} else {
chopJob.close();
chopJob = null;
@ -122,7 +125,7 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
@Override
public String getJobName() {
return "Chop Tree";
return "Chop " + name;
}
@Override

View File

@ -3,18 +3,17 @@ package xyz.valnet.hadean.gameobjects.worldobjects;
import java.util.HashSet;
import java.util.Set;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.math.Vector4i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.terrain.Terrain;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.interfaces.ITileThing;
public abstract class WorldObject extends GameObject {
// TODO make it just a box lawl
private int x;
private int y;
private int w;
@ -94,10 +93,6 @@ public abstract class WorldObject extends GameObject {
setPosition(x, y, 1, 1);
}
protected void setPosition(Box box) {
setPosition((int) box.x, (int) box.y, (int) box.w, (int) box.h);
}
protected void setPosition(int x, int y, int w, int h) {
this.x = x;
this.y = y;
@ -129,8 +124,8 @@ public abstract class WorldObject extends GameObject {
public abstract String getName();
public Box getWorldBox() {
return new Box(x, y, w, h);
public Vector4f getWorldBox() {
return new Vector4f(x, y, x + w, y + h);
}
}

View File

@ -12,8 +12,8 @@ import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.shaders.SimpleShader;
import xyz.valnet.hadean.HadeanGame;
import xyz.valnet.hadean.gameobjects.terrain.Terrain;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.pathfinding.AStarPathfinder;

View File

@ -1,23 +1,143 @@
package xyz.valnet.hadean.gameobjects.worldobjects.constructions;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.worldobjects.Buildable;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Log;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.interfaces.IItemReceiver;
import xyz.valnet.hadean.interfaces.IWorkable;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
import xyz.valnet.hadean.util.detail.BooleanDetail;
import xyz.valnet.hadean.util.detail.Detail;
import xyz.valnet.hadean.util.detail.ObjectDetail;
import xyz.valnet.hadean.util.detail.PercentDetail;
public class Bed extends Construction {
@BuildableMetadata(category = "Furniture", name = "Bed", type = BuildableMetadata.Type.SINGLE)
public class Bed extends Buildable implements IItemReceiver, IWorkable {
private int logs = 0;
private float work = 0;
private final float maxWork = 500;
private Job job = null;
@Override
public Vector2i getDimensions() {
protected Vector2i getDimensions() {
return new Vector2i(1, 2);
}
@Override
protected void create() {
super.create();
job = add(new Job("Build Bed"));
job.addStep(job.new PickupItemByPredicate(Log.LOG_PREDICATE));
job.addStep(job.new DropoffPredicateAtItemReceiver(this, Log.LOG_PREDICATE));
job.addStep(job.new Work(this));
get(JobBoard.class).postJob(job);
}
@Override
public void render() {
super.render();
Vector2i pos = getWorldPosition().xy();
if(isBuilt()) {
camera.draw(Layers.GROUND, Assets.bed, pos.x, pos.y, 1, 2);
} else {
float p = work / maxWork;
float b = 4;
Assets.flat.pushColor(Color.grey(b).withAlpha(0.5f));
camera.draw(Layers.GROUND, Assets.bed, pos.x, pos.y, 1, 2);
Assets.flat.popColor();
if(logs > 0) {
camera.drawProgressBar(p, getWorldBox());
}
// Assets.uiFrame.draw(box.x -3, box.y - 6, (int)Math.round(lerp(0, box.z + 6, p)), 4);
}
}
@Override
public String getName() {
return "Bed";
}
@Override
public boolean receive(Item item) {
if(item == null) return false;
if(!item.matches(Log.LOG_PREDICATE)) return false;
remove(item);
logs ++;
return true;
}
private boolean isBuilt() {
return work >= maxWork;
}
@Override
public boolean doWork(float dTime) {
work += dTime;
return isBuilt();
}
private Vector2i[] getBorders() {
Vector2i pos = getWorldPosition().xy();
return new Vector2i[] {
new Vector2i(pos.x, pos.y - 1),
new Vector2i(pos.x - 1, pos.y),
new Vector2i(pos.x + 1, pos.y),
new Vector2i(pos.x - 1, pos.y + 1),
new Vector2i(pos.x + 1, pos.y + 1),
new Vector2i(pos.x, pos.y + 2),
};
}
@Override
public Vector2i[] getWorkablePositions() {
return getBorders();
}
@Override
public String getJobName() {
return "Build Bed";
}
@Override
public Vector2i[] getItemDropoffLocations() {
return getBorders();
}
@Override
public Action[] getActions() {
return new Action[0];
}
@Override
public void runAction(Action action) {
}
@Override
public Detail[] getDetails() {
return new Detail[] {
new BooleanDetail("Built", isBuilt()),
new PercentDetail("Work", work / maxWork, 1),
new ObjectDetail<Integer>("Logs", logs),
};
}
@Override
public boolean isWalkable() {
return false;
@ -32,19 +152,4 @@ public class Bed extends Construction {
public void onRemove() {
}
@Override
protected IItemPredicate getBuildingMaterial() {
return Log.LOG_PREDICATE;
}
@Override
protected int getBuildingMaterialCount() {
return 1;
}
@Override
protected Sprite getDefaultSprite() {
return Assets.bed;
}
}

View File

@ -3,20 +3,15 @@ package xyz.valnet.hadean.gameobjects.worldobjects.constructions;
import java.util.ArrayList;
import java.util.List;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.jobs.Job;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.worldobjects.Buildable;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Boulder;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.interfaces.BuildType;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.IItemReceiver;
import xyz.valnet.hadean.interfaces.IWorkable;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
public abstract class Construction extends Buildable implements IItemReceiver {
@ -26,6 +21,9 @@ public abstract class Construction extends Buildable implements IItemReceiver {
protected abstract IItemPredicate getBuildingMaterial();
protected abstract int getBuildingMaterialCount();
protected Vector2i getDimensions() {
return new Vector2i(1, 1);
}
private final boolean isBuildingMaterialSatisfied() {
return containedItems.size() >= getBuildingMaterialCount();
@ -45,16 +43,17 @@ public abstract class Construction extends Buildable implements IItemReceiver {
}
if(!isBuilt()) {
Job job = get(JobBoard.class).postSimpleWorkJob(
"Build " + getName(),
new IWorkable() {
@Override
public boolean doWork(float dTime) {
work += dTime;
return isBuilt();
}
@Override
public Vector2i[] getWorkablePositions() {
return getWorldBox().getBorders();
return getWorldBox().toXYWH().asInt().getBorders();
}
@Override
@ -74,7 +73,7 @@ public abstract class Construction extends Buildable implements IItemReceiver {
return 1000;
}
public final boolean isBuilt() {
public boolean isBuilt() {
return work >= getMaxWork();
}
@ -109,57 +108,16 @@ public abstract class Construction extends Buildable implements IItemReceiver {
}
@Override
public final boolean receive(Item item) {
public boolean receive(Item item) {
if(item == null) return false;
if(!item.matches(getBuildingMaterial())) return false;
if(!item.matches(Boulder.BOULDER_PREDICATE)) return false;
remove(item);
containedItems.add(item);
// boulders ++;
return true;
}
@Override
public Vector2i[] getItemDropoffLocations() {
return getWorldBox().getBorders();
return getWorldBox().toXYWH().asInt().getBorders();
}
@Override
public void render() {
Sprite sprite = getDefaultSprite();
if(isBuilt()) {
camera.draw(Layers.TILES, sprite, getWorldPosition());
} else {
float b = 4;
Assets.flat.pushColor(Color.grey(b).withAlpha(0.5f));
camera.draw(Layers.GROUND, getDefaultSprite(), getWorldPosition());
Assets.flat.popColor();
if(getBuildProgress() > 0) {
camera.drawProgressBar(getBuildProgress(), getWorldBox());
}
}
}
protected abstract Sprite getDefaultSprite();
@Override
public BuildType getBuildType() {
return BuildType.SINGLE;
}
@Override
public String getBuildTabCategory() {
return "Buildings";
}
@Override
public String getBuildTabName() {
return getName();
}
@Override
public Action[] getActions() {
return new Action[0];
}
@Override
public void runAction(Action action) {}
}

View File

@ -1,77 +0,0 @@
package xyz.valnet.hadean.gameobjects.worldobjects.constructions;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.ui.WorkshopOrdersUI;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Log;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.IWorkshop;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
public class MasonWorkshop extends Construction implements IWorkshop {
private static Action OPEN_ORDERS = new Action("Orders");
private transient WorkshopOrdersUI ordersWindow;
@Override
protected IItemPredicate getBuildingMaterial() {
return Log.LOG_PREDICATE;
}
@Override
protected int getBuildingMaterialCount() {
return 1;
}
@Override
public boolean isWalkable() {
return false;
}
@Override
public String getName() {
return "Mason's Workshop";
}
@Override
protected Sprite getDefaultSprite() {
return Assets.testTile;
}
@Override
public Vector2i getDimensions() {
return new Vector2i(3, 3);
}
@Override
public Action[] getActions() {
if(isBuilt()) {
return new Action[] { OPEN_ORDERS };
} else return new Action[0];
}
@Override
public void runAction(Action action) {
if(action == OPEN_ORDERS) {
ordersWindow.open(this);
}
}
@Override
protected void connect() {
super.connect();
ordersWindow = get(WorkshopOrdersUI.class);
}
@Override
public String getBuildTabName() {
return "Mason";
}
@Override
public String getBuildTabCategory() {
return "Workshops";
}
}

View File

@ -1,18 +1,41 @@
package xyz.valnet.hadean.gameobjects.worldobjects.constructions;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.jobs.Job;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.jobs.SimpleWorkable;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Boulder;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.IWorkable;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
@BuildableMetadata(category = "Buildings", name = "Quarry", type = BuildableMetadata.Type.SINGLE)
public class Quarry extends Construction {
private Job digJob = null;
@Override
public void render() {
if(isBuilt()) {
camera.draw(Layers.TILES, Assets.quarry, getWorldPosition());
if(digJob != null && !digJob.isCompleted()) {
camera.drawProgressBar(digProgress, getWorldBox());
}
} else {
float b = 4;
Assets.flat.pushColor(Color.grey(b).withAlpha(0.5f));
camera.draw(Layers.GROUND, Assets.quarry, getWorldPosition());
Assets.flat.popColor();
camera.drawProgressBar(getBuildProgress(), getWorldBox());
}
}
@Override
public Vector2i getDimensions() {
return new Vector2i(3, 3);
@ -25,14 +48,32 @@ public class Quarry extends Construction {
if (digJob != null) return;
if (terrain.getTile(getWorldPosition().xy().south().east()).has(Boulder.class)) return;
digJob = get(JobBoard.class).postSimpleWorkJob(new SimpleWorkable("Mine at Quarry", 5000, () -> {
return new Vector2i[] {
getWorldPosition().xy().south().east()
};
}, (progress) -> {
digProgress = progress;
}));
digJob = get(JobBoard.class)
.postSimpleWorkJob("Mine at Quarry", new IWorkable() {
private static float MAX_WORK = 5000;
private float work = 0;
@Override
public boolean doWork(float dTime) {
work += dTime;
digProgress = work / MAX_WORK;
return work >= MAX_WORK;
}
@Override
public Vector2i[] getWorkablePositions() {
return new Vector2i[] {
getWorldPosition().xy().south().east()
};
}
@Override
public String getJobName() {
return "Mine at Quarry";
}
});
digJob.registerClosedListener(() -> {
digProgress = 0;
Vector2i dropPos = getWorldPosition().xy().south().east();
@ -77,19 +118,4 @@ public class Quarry extends Construction {
protected int getBuildingMaterialCount() {
return 0;
}
@Override
protected final Sprite getDefaultSprite() {
return Assets.quarry;
}
@Override
public void render() {
super.render();
if(!isBuilt()) return;
if(digJob != null && !digJob.isCompleted() && digProgress > 0) {
camera.drawProgressBar(digProgress, getWorldBox());
}
}
}

View File

@ -2,18 +2,48 @@ package xyz.valnet.hadean.gameobjects.worldobjects.constructions;
import java.util.EnumSet;
import xyz.valnet.engine.graphics.Sprite;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.graphics.Tile16.Direction;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.HadeanGame;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.gameobjects.worldobjects.Buildable;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Boulder;
import xyz.valnet.hadean.interfaces.BuildType;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.interfaces.IItemReceiver;
import xyz.valnet.hadean.interfaces.IPingable;
import xyz.valnet.hadean.interfaces.IWorkable;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
import xyz.valnet.hadean.util.detail.BooleanDetail;
import xyz.valnet.hadean.util.detail.Detail;
import xyz.valnet.hadean.util.detail.ObjectDetail;
import xyz.valnet.hadean.util.detail.PercentDetail;
public class Wall extends Construction implements IPingable {
@BuildableMetadata(category = "Structure", name = "Wall", type = BuildableMetadata.Type.SINGLE)
public class Wall extends Buildable implements IItemReceiver, IWorkable, IPingable {
private int boulders = 0;
private float work = 0;
private final float maxWork = 500;
private Job job = null;
@Override
protected void create() {
super.create();
job = add(new Job("Build Wall"));
if(!HadeanGame.debugView) {
job.addStep(job.new PickupItemByPredicate(Boulder.BOULDER_PREDICATE));
job.addStep(job.new DropoffPredicateAtItemReceiver(this, Boulder.BOULDER_PREDICATE));
}
job.addStep(job.new Work(this));
get(JobBoard.class).postJob(job);
}
@Override
protected void start() {
@ -21,11 +51,79 @@ public class Wall extends Construction implements IPingable {
ping();
}
@Override
public void render() {
super.render();
Vector2i pos = getWorldPosition().xy();
if(isBuilt()) {
float b = 0.7f;
Assets.flat.pushColor(Color.grey(b));
camera.draw(Layers.GROUND, Assets.wall.getTextureFor(wallSides), pos.x, pos.y);
Assets.flat.popColor();
} else {
float p = work / maxWork;
float b = 4;
Assets.flat.pushColor(Color.grey(b).withAlpha(0.5f));
camera.draw(Layers.GROUND, Assets.wall.getTextureFor(wallSides), pos.x, pos.y);
Assets.flat.popColor();
if(boulders > 0) {
camera.drawProgressBar(p, getWorldBox());
}
}
}
@Override
public String getName() {
return "Wall";
}
@Override
public boolean receive(Item item) {
if(item == null) return false;
if(!item.matches(Boulder.BOULDER_PREDICATE)) return false;
remove(item);
boulders ++;
return true;
}
private boolean isBuilt() {
return work >= maxWork;
}
@Override
public boolean doWork(float dTime) {
work += dTime;
return isBuilt();
}
private Vector2i[] getBorders() {
Vector2i pos = getWorldPosition().xy();
return new Vector2i[] {
pos.north(),
pos.east(),
pos.south(),
pos.west()
};
}
@Override
public Vector2i[] getWorkablePositions() {
return getBorders();
}
@Override
public String getJobName() {
return "Build Wall";
}
@Override
public Vector2i[] getItemDropoffLocations() {
return getBorders();
}
@Override
public Action[] getActions() {
return new Action[0];
@ -36,6 +134,19 @@ public class Wall extends Construction implements IPingable {
}
@Override
public Detail[] getDetails() {
return new Detail[] {
new BooleanDetail("Built", isBuilt()),
new PercentDetail("Work", work / maxWork, 1),
new ObjectDetail<Integer>("Logs", boulders),
new BooleanDetail("North", wallSides.contains(Direction.NORTH)),
new BooleanDetail("East", wallSides.contains(Direction.EAST)),
new BooleanDetail("South", wallSides.contains(Direction.SOUTH)),
new BooleanDetail("West", wallSides.contains(Direction.WEST)),
};
}
@Override
public boolean isWalkable() {
return !isBuilt();
@ -55,7 +166,7 @@ public class Wall extends Construction implements IPingable {
@Override
public void ping() {
Vector2i pos = getWorldBox().a.asInt();
Vector2i pos = getWorldBox().asInt().xy();
wallSides = EnumSet.noneOf(Direction.class);
Tile north = terrain.getTile(pos.x, pos.y - 1);
@ -70,34 +181,4 @@ public class Wall extends Construction implements IPingable {
Tile west = terrain.getTile(pos.x + 1, pos.y);
if(west != null && west.has(Wall.class)) wallSides.add(Direction.WEST);
}
@Override
public String getBuildTabCategory() {
return "Structure";
}
@Override
public BuildType getBuildType() {
return BuildType.LINE;
}
@Override
protected IItemPredicate getBuildingMaterial() {
return Boulder.BOULDER_PREDICATE;
}
@Override
protected int getBuildingMaterialCount() {
return 1;
}
@Override
protected Sprite getDefaultSprite() {
return Assets.wall.getTextureFor(EnumSet.noneOf(Direction.class));
}
@Override
protected float getMaxWork() {
return super.getMaxWork();
}
}

View File

@ -2,9 +2,9 @@ package xyz.valnet.hadean.gameobjects.worldobjects.items;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4i;
import xyz.valnet.hadean.gameobjects.jobs.Job;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.interfaces.IItemPredicate;
import xyz.valnet.hadean.interfaces.ISelectable;

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn;
package xyz.valnet.hadean.gameobjects.worldobjects.pawn;
import java.io.Serializable;

View File

@ -1,9 +1,9 @@
package xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn;
package xyz.valnet.hadean.gameobjects.worldobjects.pawn;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.jobs.Job;
import xyz.valnet.hadean.gameobjects.jobs.Job.JobStep;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.Job.JobStep;
import xyz.valnet.hadean.gameobjects.JobBoard;
public class JobActivity extends Activity {

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn;
package xyz.valnet.hadean.gameobjects.worldobjects.pawn;
import java.io.Serializable;

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn;
package xyz.valnet.hadean.gameobjects.worldobjects.pawn;
import static xyz.valnet.hadean.util.detail.Detail.*;
@ -6,14 +6,14 @@ import java.util.ArrayList;
import java.util.List;
import xyz.valnet.engine.graphics.Color;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.util.Names;
import xyz.valnet.hadean.HadeanGame;
import xyz.valnet.hadean.gameobjects.Clock;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.terrain.Terrain;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.worldobjects.agents.Agent;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.interfaces.IItemPredicate;
@ -154,9 +154,9 @@ public class Pawn extends Agent {
}
@Override
public Box getWorldBox() {
public Vector4f getWorldBox() {
Vector2f pos = getCalculatedPosition();
return new Box(pos, 1, 1);
return new Vector4f(pos.x, pos.y, pos.x+1, pos.y+1);
}
@Override

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn;
package xyz.valnet.hadean.gameobjects.worldobjects.pawn;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.util.Math.WeightedAverage;

View File

@ -1,8 +1,8 @@
package xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn;
package xyz.valnet.hadean.gameobjects.worldobjects.pawn;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.hadean.gameobjects.terrain.Terrain;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.Tile;
// TODO actually implement this activity.
public class WanderActivity extends Activity {

View File

@ -1,23 +0,0 @@
package xyz.valnet.hadean.gameobjects.worldobjects.zones;
import xyz.valnet.hadean.gameobjects.worldobjects.Buildable;
import xyz.valnet.hadean.interfaces.BuildType;
public abstract class Zone extends Buildable {
@Override
public String getBuildTabCategory() {
return "Zones";
}
@Override
public BuildType getBuildType() {
return BuildType.AREA;
}
@Override
public boolean isWalkable() {
return true;
}
}

View File

@ -1,7 +0,0 @@
package xyz.valnet.hadean.interfaces;
public enum BuildType {
AREA,
LINE,
SINGLE
}

View File

@ -0,0 +1,18 @@
package xyz.valnet.hadean.interfaces;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface BuildableMetadata {
public enum Type {
AREA,
LINE,
SINGLE
}
public String name();
public String category();
public Type type() default Type.AREA;
}

View File

@ -1,11 +1,8 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.engine.math.TileBox;
public interface IBuildLayerListener {
public void update(TileBox box);
public void build(TileBox box);
public void update(int x, int y, int w, int h);
public void build(int x, int y, int w, int h);
public void build(int x, int y);
public void cancel();
}

View File

@ -1,18 +1,8 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.engine.math.TileBox;
import xyz.valnet.engine.math.Vector2i;
public interface IBuildable {
public void buildAt(TileBox box);
public String getBuildTabCategory();
public BuildType getBuildType();
public String getBuildTabName();
public default Vector2i getDimensions() {
return null;
}
public void buildAt(int x, int y, int w, int h);
public void buildAt(int x, int y);
}

View File

@ -1,6 +1,6 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.engine.math.Box;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.detail.Detail;
@ -22,7 +22,7 @@ public interface ISelectable {
}
}
public Box getWorldBox();
public Vector4f getWorldBox();
public Action[] getActions();
public void runAction(Action action);
public Detail[] getDetails();

View File

@ -1,6 +1,6 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.hadean.gameobjects.terrain.Tile;
import xyz.valnet.hadean.gameobjects.Tile;
public interface ITileThing {
public boolean isWalkable();

View File

@ -1,5 +0,0 @@
package xyz.valnet.hadean.interfaces;
public interface IWorkshop extends ISelectable {
}

View File

@ -2,14 +2,12 @@ package xyz.valnet.hadean.scenes;
import xyz.valnet.engine.scenegraph.SceneGraph;
import xyz.valnet.engine.util.Names;
import xyz.valnet.hadean.gameobjects.ui.BottomBar;
import xyz.valnet.hadean.gameobjects.BottomBar;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.Clock;
import xyz.valnet.hadean.gameobjects.jobs.JobBoard;
import xyz.valnet.hadean.gameobjects.jobs.WorkOrderManager;
import xyz.valnet.hadean.gameobjects.ui.SelectionUI;
import xyz.valnet.hadean.gameobjects.ui.WorkshopOrdersUI;
import xyz.valnet.hadean.gameobjects.terrain.Terrain;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.SelectionUI;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.inputlayer.BuildLayer;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.ui.ExclusivityManager;
@ -18,7 +16,7 @@ import xyz.valnet.hadean.gameobjects.ui.tabs.BuildTab;
import xyz.valnet.hadean.gameobjects.ui.tabs.DebugTab;
import xyz.valnet.hadean.gameobjects.ui.tabs.JobBoardTab;
import xyz.valnet.hadean.gameobjects.ui.tabs.MenuTab;
import xyz.valnet.hadean.gameobjects.worldobjects.agents.pawn.Pawn;
import xyz.valnet.hadean.gameobjects.worldobjects.pawn.Pawn;
// TODO BIG IDEAS
// have caches of types that ill need (Like IMouseListener)
@ -45,18 +43,16 @@ public class GameScene extends SceneGraph {
objects.add(new Pawn());
}
objects.add(new WorkOrderManager());
objects.add(new ExclusivityManager());
objects.add(new SelectionLayer());
objects.add(new SelectionUI());
objects.add(new BuildLayer());
objects.add(new WorkshopOrdersUI());
objects.add(new SelectionUI());
objects.add(new HoverQuery());
objects.add(new BottomBar());
objects.add(new ExclusivityManager());
objects.add(new BuildTab());
objects.add(new JobBoardTab());
objects.add(new DebugTab());

View File

@ -6,35 +6,4 @@ public class Action {
public Action(String name) {
this.name = name;
}
public static Action[] mergeActions(Action[] a, Action[] b) {
Action[] c = new Action[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
public static Action[] mergeActions(Action[] a, Action[] b, Action[] c) {
Action[] d = new Action[a.length + b.length + c.length];
System.arraycopy(a, 0, d, 0, a.length);
System.arraycopy(b, 0, d, a.length, b.length);
System.arraycopy(c, 0, d, a.length + b.length, c.length);
return c;
}
public static Action[] mergeActions(Action[] ... args) {
if(args.length == 1) return new Action[0];
if(args.length == 1) return args[0];
if(args.length == 2) return mergeActions(args[0], args[1]);
if(args.length == 3) return mergeActions(args[0], args[1], args[2]);
Action[][] merge = new Action[3][];
Action[][] rest = new Action[args.length - 3][];
System.arraycopy(args, 0, merge, 0, 3);
System.arraycopy(args, 3, rest, 0, rest.length);
Action[] first = mergeActions(merge);
Action[] merged = mergeActions(rest);
return mergeActions(first, merged);
}
}

View File

@ -100,7 +100,7 @@ public class Assets {
egg = new Sprite(atlas, 8, 104, 8, 8);
bigRock = new Sprite(atlas, 16, 104, 8, 8);
lilPickaxe = new Sprite(atlas, 8, 120, 16, 16);
testTile = new Sprite(atlas, 64, 112, 16, 16);
testTile = new Sprite(atlas, 16, 16, 64, 112);
quarry = new Sprite(atlas, 88, 64, 24, 24);
Map<Character, Sprite> charset = new HashMap<Character, Sprite>();

View File

@ -0,0 +1,41 @@
package xyz.valnet.hadean.util;
import java.io.Serializable;
public class SmartBoolean implements Serializable {
private boolean value;
public interface IListener extends Serializable {
public default void rise() {}
public default void fall() {}
public default void changed() {}
}
private IListener isbl;
public SmartBoolean(boolean v, IListener isbl) {
value = v;
this.isbl = isbl;
}
public void set(boolean b) {
if(value != b) {
value = b;
isbl.changed();
if(b) {
isbl.rise();
} else {
isbl.fall();
}
}
}
public void toggle() {
set(!value);
}
public boolean value() {
return value;
}
}