new job system. QoL things

pull/1/head
valyrie97 2022-12-26 14:39:29 -05:00
parent 95cf571450
commit a1fcec4f26
44 changed files with 724 additions and 725 deletions

View File

@ -1,3 +1,4 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
"java.configuration.updateBuildConfiguration": "automatic",
"java.dependency.packagePresentation": "hierarchical"
}

View File

@ -1,6 +1,5 @@
package xyz.valnet.engine;
import org.lwjgl.*;
import org.lwjgl.glfw.*;
import org.lwjgl.opengl.*;
import org.lwjgl.system.*;
@ -29,7 +28,6 @@ public class App {
private Game game;
public void run() {
System.out.println("Hello LWJGL " + Version.getVersion() + "!");
init();
loop();
@ -55,7 +53,7 @@ public class App {
// Configure GLFW
glfwDefaultWindowHints(); // optional, the current window hints are already the default
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); // the window will stay hidden after creation
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE); // the window will be resizable
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // the window will be resizable
// Create the window
window = glfwCreateWindow(width, height, "Hello World!", NULL, NULL);
@ -86,7 +84,6 @@ public class App {
game.mouseUp(button);
}
// TODO deprecate these.
if(button >= 3) return;
if(button == GLFW_MOUSE_BUTTON_LEFT) { mouseLeft = action == 1; return; }
if(button == GLFW_MOUSE_BUTTON_RIGHT) { mouseRight = action == 1; return; }

View File

@ -1,5 +1,7 @@
package xyz.valnet.engine.graphics;
import xyz.valnet.engine.math.Vector4f;
public class Tile9 {
private final Sprite topLeft;
@ -34,6 +36,10 @@ public class Tile9 {
this.bottomRight = bottomRight;
}
public void draw(Vector4f box) {
draw((int)box.x, (int)box.y, (int)box.z, (int)box.w);
}
public void draw(int x, int y, int w, int h) {
int a = w < 0 ? x + w : x; // top left x
int b = h < 0 ? y + h : y; // top left y

View File

@ -14,4 +14,12 @@ public class Vector2f {
this.y = y;
}
public Vector2i asInt() {
return new Vector2i((int)x, (int)y);
}
public boolean equals(Vector2f v) {
return x == v.x && y == v.y;
}
}

View File

@ -33,4 +33,8 @@ public class Vector2i {
return (float) Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
}
public Vector2f asFloat() {
return new Vector2f(x, y);
}
}

View File

@ -34,4 +34,22 @@ public class Vector4f {
return x >= this.x && x < this.x + this.z && y >= this.y && y < this.y + this.w;
}
public Vector4f toAABB() {
return new Vector4f(
x,
y,
x + z,
y + w
);
}
public Vector4f toXYWH() {
return new Vector4f(
x,
y,
z - x,
w - y
);
}
}

View File

@ -25,12 +25,13 @@ public class GameObject implements IRenderable, ITickable {
return this.scene.getAll(clazz);
}
protected final void add(GameObject obj) {
protected final <T extends GameObject> T add(T obj) {
if(obj.inScene()) {
System.out.println(obj + " is already in the scene. not adding twice...");
return;
return obj;
}
scene.add(obj);
return obj;
}
@Override

View File

@ -6,4 +6,11 @@ public class Math {
if(n <= 0) return a;
return a + (b - a) * n;
}
public static float lerp(float minT, float maxT, float t, float outMin, float outMax) {
if (t <= minT) return outMin;
if (t >= maxT) return outMax;
float scale = (t - minT) / (maxT - minT);
return outMin + (scale * (outMax - outMin));
}
}

View File

@ -12,7 +12,7 @@ import xyz.valnet.engine.Game;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Matrix4f;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.scenes.GameScene;
import xyz.valnet.hadean.scenes.MenuScene;
import xyz.valnet.hadean.util.Assets;
@ -27,7 +27,7 @@ public class HadeanGame extends Game {
@Override
public void start() {
Assets.flat.pushColor(Vector4f.one);
changeScene(new MenuScene());
changeScene(new GameScene());
}
@Override

View File

@ -0,0 +1,19 @@
package xyz.valnet.hadean.designation;
import xyz.valnet.hadean.gameobjects.worldobjects.Tree;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
@BuildableMetadata(category = "Designations", name = "Chop Trees")
public class CutTreesDesignation extends Designation<Tree> {
@Override
protected Class<Tree> getType() {
return Tree.class;
}
@Override
protected void designate(Tree thing) {
thing.runAction(Tree.ACTION_CHOP);
}
}

View File

@ -0,0 +1,38 @@
package xyz.valnet.hadean.designation;
import java.util.List;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.IBuildable;
import xyz.valnet.hadean.interfaces.ISelectable;
public abstract class Designation<T extends ISelectable> extends GameObject implements IBuildable {
@Override
@SuppressWarnings("unchecked")
public void buildAt(int x, int y, int w, int h) {
Class<T> type = getType();
List<T> things = getAll(type);
for(ISelectable thing : things) {
Vector4f box = thing.getWorldBox();
if(rectanglesIntersect(x, y, x + w, y + h, box.x, box.y, box.z, box.w))
designate((T) thing);
}
}
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

@ -3,7 +3,6 @@ package xyz.valnet.hadean.gameobjects;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.graphics.Sprite;
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.hadean.interfaces.IWorldBoundsAdapter;
@ -11,7 +10,7 @@ import xyz.valnet.hadean.interfaces.IWorldBoundsAdapter;
public class Camera extends GameObject {
private int tileWidth = 16;
// TODO link these in some way to the real resolution.
// TODO link these in some way to the real resolution. lot of work here.
private int screenWidth = 1024, screenHeight = 576;
private Vector2f focus = new Vector2f(0, 0);
@ -39,8 +38,13 @@ public class Camera extends GameObject {
return new Vector2f((x - screenWidth / 2 + focus.x * tileWidth) / tileWidth, (y - screenHeight / 2 + focus.y * tileWidth) / tileWidth);
}
public Vector2i screen2worldI(float x, float y) {
return new Vector2i((int)Math.floor((x - screenWidth / 2 + focus.x * tileWidth) / tileWidth), (int)Math.floor((y - screenHeight / 2 + focus.y * tileWidth) / tileWidth));
public Vector4f world2Screen(Vector4f input) {
return new Vector4f(
input.x * tileWidth + screenWidth / 2 - focus.x * tileWidth,
input.y * tileWidth + screenHeight / 2 - focus.y * tileWidth,
input.z * tileWidth + screenWidth / 2 - focus.x * tileWidth,
input.w * tileWidth + screenHeight / 2 - focus.y * tileWidth
);
}
@Deprecated

View File

@ -0,0 +1,112 @@
package xyz.valnet.hadean.gameobjects;
import java.util.ArrayList;
import java.util.List;
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.hadean.gameobjects.worldobjects.Stockpile;
import xyz.valnet.hadean.gameobjects.worldobjects.items.Item;
import xyz.valnet.hadean.interfaces.IWorkable;
public class Job extends GameObject {
private Terrain terrain;
private Job that = this;
public abstract class JobStep {
public abstract Vector2f getLocation();
public void next() {
that.nextStep();
}
}
public class PickupItem extends JobStep {
public Item item;
public Vector2f[] locations;
public PickupItem(Item item, Vector2f[] possibleLocations) {
this.item = item;
}
@Override
public Vector2f getLocation() {
return item.getWorldPosition();
}
}
public class DropoffAtStockpile extends JobStep {
public Item item;
public DropoffAtStockpile(Item item) {
this.item = item;
}
public Vector2f getLocation() {
Stockpile pile = that.get(Stockpile.class);
Vector4f box = pile.getWorldBox();
return new Vector2f(box.x, box.y);
}
}
public class Work extends JobStep {
public IWorkable subject;
public Work(IWorkable subject) {
this.subject = subject;
}
@Override
public Vector2f getLocation() {
return subject.getWorkablePositions()[0].asFloat();
}
public boolean doWork() {
return subject.doWork();
}
}
private List<JobStep> steps;
private String name;
private int step;
public void reset() {
step = 0;
}
@Override
public void start() {
this.terrain = get(Terrain.class);
}
public Job(String name) {
this.steps = new ArrayList<JobStep>();
this.name = name;
}
public void addStep(JobStep step) {
steps.add(step);
}
public Vector2i getLocation() {
if(steps.size() == 0) throw new Error("Cannot get location of job with no steps");
JobStep step = steps.get(0);
return step.getLocation().asInt();
}
public void nextStep() {
step ++;
if(isCompleted()) get(JobBoard.class).completeJob(this);
}
public boolean isCompleted() {
return step >= steps.size();
}
public JobStep getCurrentStep() {
if(step >= steps.size()) return null;
return steps.get(step);
}
public String getJobName() {
return name;
}
}

View File

@ -10,24 +10,29 @@ import java.util.Map.Entry;
import java.util.Set;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.IJob;
import xyz.valnet.hadean.interfaces.IWorkable;
import xyz.valnet.hadean.interfaces.IWorker;
import xyz.valnet.hadean.pathfinding.IPathfinder;
import xyz.valnet.hadean.pathfinding.Path;
import xyz.valnet.hadean.util.Pair;
public class JobBoard extends GameObject {
private Set<IJob> availableJobs = new HashSet<IJob>();
private Map<IWorker, IJob> allocations = new HashMap<IWorker, IJob>();
private Set<Job> availableJobs = new HashSet<Job>();
private List<Job> toRemove = new ArrayList<Job>();
private Map<IWorker, Job> allocations = new HashMap<IWorker, Job>();
public void postJob(IJob job) {
public Job postSimpleWorkJob(String name, IWorkable subject) {
Job job = add(new Job(name));
job.addStep(job.new Work(subject));
postJob(job);
return job;
}
public void postJob(Job job) {
availableJobs.add(job);
}
public void rescindJob(IJob job) {
public void rescindJob(Job job) {
if(allocations.values().contains(job)) {
List<IWorker> toFire = new ArrayList<IWorker>();
@ -49,27 +54,21 @@ public class JobBoard extends GameObject {
public void requestJob(IWorker worker) {
// TODO worker has capabilities?
Vector2f workerLocation = worker.getLocation();
IPathfinder pathfinder = worker.getPathfinder();
Vector2f workerLocation = worker.getWorldPosition();
List<IJob> workables = availableJobs
List<Job> workables = availableJobs
.stream()
// filter available job by the ones that currently have work
// TODO seems like this should be removed at some point
// and jobs should post / rescind when they need to
.filter(workable -> workable.hasWork())
// calculate our workers distance to each
.map(workable -> new Pair<IJob, Float>(
workable,
workable.getLocation().distanceTo(
.map(job -> new Pair<Job, Float>(
job,
job.getLocation().distanceTo(
(int) workerLocation.x,
(int) workerLocation.y
)
))
// sort the jobs by their distance from the worker
.sorted(new Comparator<Pair<IJob, Float>>() {
.sorted(new Comparator<Pair<Job, Float>>() {
@Override
public int compare(Pair<IJob, Float> a, Pair<IJob, Float> b) {
public int compare(Pair<Job, Float> a, Pair<Job, Float> b) {
if(a.second() > b.second()) return 1;
if(b.second() > a.second()) return -1;
return 0;
@ -81,38 +80,41 @@ public class JobBoard extends GameObject {
if(workables.size() > 0) {
for(IJob job : workables) {
if(!job.hasWork()) continue;
Vector2i[] workablePositions = job.getWorkablePositions();
Path bestPathToJob = pathfinder.getBestPath(
new Vector2i((int)Math.floor(workerLocation.x), (int)Math.floor(workerLocation.y)),
workablePositions
);
if(bestPathToJob == null) continue;
// it is decided. job is good, and path is hype
worker.setPath(bestPathToJob);
availableJobs.remove(job);
allocations.put(worker, job);
return;
}
Job firstJob = workables.get(0);
availableJobs.remove(firstJob);
allocations.put(worker, firstJob);
return;
}
}
public void completeJob(Job job) {
this.rescindJob(job);
}
public void completeJob(IWorker worker) {
if(!workerHasJob(worker)) return;
rescindJob(getJob(worker));
}
@Override
public void update(float dTime) {
List<IJob> toRemove = new ArrayList<IJob>();
for(IJob job : allocations.values()) {
if(!job.hasWork()) {
toRemove.add(job);
for(Job job : toRemove) {
if(allocations.values().contains(job)) {
// I AM NOT SURE THIS WORKS
allocations.values().remove(job);
}
if(availableJobs.contains(job)) {
availableJobs.remove(job);
}
}
for(IJob job : toRemove) {
rescindJob(job);
}
toRemove.clear();
}
public IJob getJob(IWorker worker) {
public boolean workerHasJob(IWorker worker) {
return allocations.containsKey(worker);
}
public Job getJob(IWorker worker) {
if(allocations.containsKey(worker)) {
return allocations.get(worker);
} else return null;
@ -123,11 +125,11 @@ public class JobBoard extends GameObject {
String takenJobsString = "";
String availableJobsString = "";
for(Entry<IWorker, IJob> allocation : allocations.entrySet()) {
for(Entry<IWorker, Job> allocation : allocations.entrySet()) {
takenJobsString += " " + allocation.getKey().getName() + ": " + allocation.getValue().getJobName() + "\n";
}
for(IJob job : availableJobs) {
for(Job job : availableJobs) {
availableJobsString += " " + job.getJobName() + "\n";
}

View File

@ -7,7 +7,7 @@ import java.util.List;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.engine.scenegraph.IMouseCaptureArea;
import xyz.valnet.hadean.gameobjects.inputlayer.Selection;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.input.Button;
import xyz.valnet.hadean.input.IButtonListener;
import xyz.valnet.hadean.input.SimpleButton;
@ -30,7 +30,7 @@ public class SelectionUI extends GameObject implements ISelectionChangeListener,
private Button[] actionButtons = ACTIONS_BUTTONS_NULL;
private Selection selectionManager;
private SelectionLayer selectionManager;
private final int width = 300, height = 200;
private final int padding = 10;
private final int actionButtonSize = 100;
@ -44,7 +44,7 @@ public class SelectionUI extends GameObject implements ISelectionChangeListener,
private List<ISelectable> newSelection = null;;
public void start() {
selectionManager = get(Selection.class);
selectionManager = get(SelectionLayer.class);
selectionManager.subscribe(this);
}

View File

@ -1,58 +0,0 @@
package xyz.valnet.hadean.gameobjects;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ITileThing;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
public class Stockpile extends WorldObject implements ITileThing, ISelectable {
private WorldObject thing;
public boolean isFree() {
return thing == null;
}
@Override
public void render() {
camera.draw(Layers.GROUND, Assets.stockpile, x, y);
}
@Override
public boolean isWalkable() {
return true;
}
@Override
public boolean shouldRemove() {
return false;
}
@Override
public void onRemove() {
}
@Override
public Vector4f getWorldBox() {
return new Vector4f(x, y, x+1, y+1);
}
@Override
public Action[] getActions() {
return new Action[] {};
}
@Override
public void runAction(Action action) {
}
@Override
public String details() {
return "";
}
}

View File

@ -1,5 +1,6 @@
package xyz.valnet.hadean.gameobjects;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.interfaces.IWorldBoundsAdapter;
@ -37,6 +38,10 @@ public class Terrain extends GameObject implements IPathable, IWorldBoundsAdapte
return tiles[x][y];
}
public Tile getTile(Vector2i pos) {
return getTile(pos.x, pos.y);
}
// TODO implement directionality. even the pathfinder doesnt give this info...
@Override
public boolean isWalkable(int x, int y, int fromX, int fromY) {

View File

@ -43,12 +43,7 @@ public class Tile extends WorldObject implements IWorkable {
stuff.add(tree);
add(tree);
}
// if(Math.random() > 0.98) {
// Log log = new Log(x, y);
// stuff.add(log);
// add(log);
// }
}
public void placeThing(ITileThing thing) {
@ -58,7 +53,8 @@ public class Tile extends WorldObject implements IWorkable {
}
if(thing instanceof FarmPlot) {
desiredTill = true;
get(JobBoard.class).postJob(this);
get(JobBoard.class).postSimpleWorkJob("Till Soil", this);
}
}
@ -107,11 +103,6 @@ public class Tile extends WorldObject implements IWorkable {
desiredTill = till;
}
@Override
public boolean hasWork() {
return desiredTill && tillLevel < 1f;
}
@Override
public Vector2i[] getWorkablePositions() {
return new Vector2i[] {
@ -127,18 +118,29 @@ public class Tile extends WorldObject implements IWorkable {
};
}
@Override
public Vector2i getLocation() {
return new Vector2i(x, y);
}
@Override
public String getJobName() {
return "Till Soil";
}
@Override
public void doWork() {
public boolean doWork() {
tillLevel += 0.005f;
tillLevel = Math.min(tillLevel, 1);
return tillLevel >= 1;
}
@Override
public String getName() {
if (tillLevel == 0) {
return "Ground";
} else if (tillLevel < 1) {
return "Tilled Soil (" + Math.floor(tillLevel * 100) + "%)";
} else return "Tilled Soil";
}
@Override
public Vector4f getWorldBox() {
return new Vector4f(x, y, x+1, y+1);
}
}

View File

@ -1,14 +1,12 @@
package xyz.valnet.hadean.gameobjects.inputlayer;
import xyz.valnet.engine.App;
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.hadean.gameobjects.Camera;
import xyz.valnet.hadean.interfaces.IBuildLayerListener;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
public class BuildLayer extends GameObject implements IMouseCaptureArea {
@ -46,7 +44,7 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea {
}
private void broadcastWorldCoords() {
Vector2i worldcoords = camera.screen2worldI(App.mouseX, App.mouseY);
Vector2i worldcoords = camera.screen2world(App.mouseX, App.mouseY).asInt();
if(mouseDown) {
Vector2i[] ords = orderCoords(new Vector2i(x, y), worldcoords);
listener.update(ords[0].x, ords[0].y, ords[2].x + 1, ords[2].y + 1);
@ -80,7 +78,7 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea {
listener.cancel();
deactiveate();
} else if(button == 0 && active && hovered) {
Vector2i worldcoords = camera.screen2worldI(App.mouseX, App.mouseY);
Vector2i worldcoords = camera.screen2world(App.mouseX, App.mouseY).asInt();
mouseDown = true;
screenX = App.mouseX;
screenY = App.mouseY;
@ -92,7 +90,7 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea {
@Override
public void mouseUp(int button) {
if(button == 0 && active && mouseDown) {
Vector2i worldcoords = camera.screen2worldI(App.mouseX, App.mouseY);
Vector2i worldcoords = camera.screen2world(App.mouseX, App.mouseY).asInt();
mouseDown = false;
int x1 = x;
int y1 = y;
@ -102,7 +100,7 @@ public class BuildLayer extends GameObject implements IMouseCaptureArea {
int minY = Math.min(y1, y2);
int maxX = Math.max(x1, x2);
int maxY = Math.max(y1, y2);
listener.select(minX, minY, maxX, maxY);
listener.build(minX, minY, maxX, maxY);
}
}

View File

@ -17,13 +17,13 @@ import xyz.valnet.hadean.util.Layers;
import static xyz.valnet.engine.util.Math.lerp;
public class Selection extends GameObject implements IMouseCaptureArea {
public class SelectionLayer extends GameObject implements IMouseCaptureArea {
public Vector2f initialCoords;
private Camera camera;
private float animation = 0;
private float animationMax = 15;
private float animationAmplitude = 0.3f;
private float animationMax = 30;
private float animationAmplitude = 0.2f;
private List<ISelectionChangeListener> listeners = new ArrayList<ISelectionChangeListener>();
@Override

View File

@ -0,0 +1,52 @@
package xyz.valnet.hadean.gameobjects.ui;
import java.util.ArrayList;
import java.util.List;
import xyz.valnet.engine.App;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.util.Assets;
public class HoverQuery extends GameObject {
private Camera camera;
@Override
public void start() {
super.start();
camera = get(Camera.class);
}
private List<String> thingStrings = new ArrayList<String>();
@Override
public void update(float dTime) {
Vector2f position = camera.screen2world(App.mouseX, App.mouseY);
thingStrings.clear();
for(WorldObject obj : getAll(WorldObject.class)) {
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());
}
}
}
@Override
public void render() {
int i = 16;
for(String thingString : thingStrings) {
Assets.font.drawString(thingString, 16, i);
i += 14;
}
}
}

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.tabs;
package xyz.valnet.hadean.gameobjects.ui.tabs;
import static xyz.valnet.engine.util.Math.lerp;
@ -21,7 +21,7 @@ import xyz.valnet.hadean.gameobjects.BottomBar;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.inputlayer.BuildLayer;
import xyz.valnet.hadean.gameobjects.inputlayer.Selection;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.worldobjects.FarmPlot;
import xyz.valnet.hadean.input.Button;
import xyz.valnet.hadean.input.IButtonListener;
@ -39,7 +39,7 @@ import xyz.valnet.hadean.util.SmartBoolean;
public class BuildTab extends Tab implements ISelectionChangeListener, IMouseCaptureArea, IButtonListener {
private Selection selection;
private SelectionLayer selection;
private BuildLayer buildLayer;
private Camera camera;
private Terrain terrain;
@ -120,7 +120,7 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IMouseCap
public void start() {
super.start();
buildLayer = get(BuildLayer.class);
selection = get(Selection.class);
selection = get(SelectionLayer.class);
camera = get(Camera.class);
terrain = get(Terrain.class);
@ -158,15 +158,16 @@ public class BuildTab extends Tab implements ISelectionChangeListener, IMouseCap
}
@Override
public void select(int x1, int y1, int x2, int y2) {
public void build(int x1, int y1, int x2, int y2) {
int ix1 = x1;
int iy1 = y1;
int ix2 = x2;
int iy2 = y2;
try {
IBuildable building = selectedBuildable.newInstance();
GameObject go = (GameObject) building;
add(go);
if(building instanceof GameObject) {
add((GameObject) building);
}
building.buildAt(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
} catch (Exception e) {
System.out.println(e);

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.tabs;
package xyz.valnet.hadean.gameobjects.ui.tabs;
import static xyz.valnet.engine.util.Math.lerp;
@ -8,7 +8,7 @@ import java.util.List;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.hadean.gameobjects.BottomBar;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.inputlayer.Selection;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ISelectionChangeListener;
import xyz.valnet.hadean.util.Assets;
@ -17,7 +17,7 @@ import xyz.valnet.hadean.util.SmartBoolean;
public class JobBoardTab extends Tab implements ISelectionChangeListener {
private Selection selection;
private SelectionLayer selection;
private JobBoard jobBoard;
private SmartBoolean opened;
@ -37,7 +37,7 @@ public class JobBoardTab extends Tab implements ISelectionChangeListener {
@Override
public void start() {
super.start();
selection = get(Selection.class);
selection = get(SelectionLayer.class);
jobBoard = get(JobBoard.class);
opened = new SmartBoolean(false, new SmartBoolean.IListener() {

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.tabs;
package xyz.valnet.hadean.gameobjects.ui.tabs;
public class MenuTab extends Tab {

View File

@ -1,4 +1,4 @@
package xyz.valnet.hadean.gameobjects.tabs;
package xyz.valnet.hadean.gameobjects.ui.tabs;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.BottomBar;

View File

@ -12,31 +12,8 @@ import xyz.valnet.hadean.util.Layers;
@BuildableMetadata(category = "Zones", name = "Farm Plot")
public class FarmPlot extends WorldObject implements ISelectable, ITileThing, IBuildable {
// private float progress = 0f;
// private int stage = 0;
// private boolean planted = false;
// private boolean mature = false;
// private static int STAGE_LENGTH = 1000;
// private static int MAX_STAGES = 4;
// private JobBoard board;
private int w, h;
@Override
public void render() {
// camera.draw(Layers.TILES, Assets.farmPlot, x, y);
// if(planted) {
// if(stage > 1) {
// camera.draw(Layers.AIR, Assets.growingRice[stage], x, y - 1, 1, 2);
// } else {
// camera.draw(Layers.AIR, Assets.growingRice[stage], x, y);
// }
// }
}
@Override
public void renderAlpha() {
if(!visible) return;
@ -45,64 +22,6 @@ public class FarmPlot extends WorldObject implements ISelectable, ITileThing, IB
Assets.flat.popColor();
}
@Override
public void update(float dTime) {
super.update(dTime);
// if(stage == MAX_STAGES - 1) {
// return;
// } if(planted) {
// if(Math.random() > 0.95f) {
// progress += 10;
// if(progress >= STAGE_LENGTH) {
// stage ++;
// progress = 0;
// if(stage == MAX_STAGES - 1) {
// mature = true;
// board.postJob(this);
// }
// }
// }
// } else if (progress >= STAGE_LENGTH) {
// planted = true;
// progress = 0;
// }
}
@Override
public void start() {
super.start();
// board = get(JobBoard.class);
// board.postJob(this);
}
// @Override
// public boolean hasWork() {
// // return !planted || mature;
// }
// @Override
// public Vector2i[] getWorkablePositions() {
// return new Vector2i[] {
// new Vector2i((int) x, (int) y + 1),
// new Vector2i((int) x, (int) y - 1),
// new Vector2i((int) x + 1, (int) y),
// new Vector2i((int) x - 1, (int) y)
// };
// }
// @Override
// public Vector2i getLocation() {
// return new Vector2i((int) x, (int) y);
// }
// @Override
// public String getJobName() {
// return planted ? "Harvest Rice" : "Plant Rice";
// }
@Override
public Vector4f getWorldBox() {
return new Vector4f(x, y, x + w, y + h);
@ -126,23 +45,9 @@ public class FarmPlot extends WorldObject implements ISelectable, ITileThing, IB
@Override
public String details() {
return "";
}
// @Override
// public void doWork() {
// // progress ++;
// // if(mature && progress >= STAGE_LENGTH) {
// // mature = false;
// // planted = false;
// // stage = 0;
// // if(Math.random() < 0.3) {
// // getTile().placeThing(new Rice((int)x, (int)y));
// // }
// // }
// }
@Override
public boolean isWalkable() {
return true;
@ -167,7 +72,7 @@ public class FarmPlot extends WorldObject implements ISelectable, ITileThing, IB
this.h = h;
System.out.println("<" + x + ", " + y + ", " + w + ", " + h + ">");
System.out.println(inScene());
terrain.getTile(x, y).placeThing(this);
for(int i = x; i < x + w; i ++) {
for(int j = y; j < y + h; j ++) {
terrain.getTile(i, j).placeThing(this);
@ -175,4 +80,9 @@ public class FarmPlot extends WorldObject implements ISelectable, ITileThing, IB
}
}
@Override
public String getName() {
return "Farm Plot";
}
}

View File

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

View File

@ -1,42 +1,17 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.Stockpile;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.interfaces.IHaulable;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ITileThing;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
import xyz.valnet.hadean.util.SmartBoolean;
import xyz.valnet.hadean.util.SmartBoolean.IListener;
public class Log extends WorldObject implements ITileThing, ISelectable, IHaulable {
private SmartBoolean haul;
private JobBoard jobboard;
public class Log extends WorldObject implements ITileThing, ISelectable {
@Override
public void start() {
super.start();
jobboard = get(JobBoard.class);
Log that = this;
haul = new SmartBoolean(false, new IListener() {
@Override
public void rise() {
jobboard.postJob(that);
}
@Override
public void fall() {
jobboard.rescindJob(that);
}
});
}
public Log(int x, int y) {
@ -47,9 +22,6 @@ public class Log extends WorldObject implements ITileThing, ISelectable, IHaulab
@Override
public void render() {
camera.draw(Layers.GROUND, Assets.log, x, y);
if(haul.value()) {
camera.draw(Layers.MARKERS, Assets.haulArrow, x, y);
}
}
@Override
@ -81,9 +53,7 @@ public class Log extends WorldObject implements ITileThing, ISelectable, IHaulab
@Override
public void runAction(Action action) {
if(action == ACTION_HAUL) {
haul.toggle();
}
}
@Override
@ -92,41 +62,8 @@ public class Log extends WorldObject implements ITileThing, ISelectable, IHaulab
}
@Override
public boolean hasWork() {
return haul.value();
}
@Override
public Vector2i[] getWorkablePositions() {
return new Vector2i[] {
new Vector2i((int)x + 1, (int)y),
new Vector2i((int)x - 1, (int)y),
new Vector2i((int)x, (int)y + 1),
new Vector2i((int)x, (int)y - 1)
};
}
@Override
public Vector2i getLocation() {
return new Vector2i((int)x, (int)y);
}
@Override
public Log take() {
haul.set(false);
Tile tile = terrain.getTile((int)x, (int)y);
tile.remove(this);
return this;
}
@Override
public Tile getDestination() {
return get(Stockpile.class).getTile();
}
@Override
public String getJobName() {
return "Haul Log";
public String getName() {
return "Log";
}
}

View File

@ -1,307 +1,121 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import static org.lwjgl.opengl.GL11.GL_LINES;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glVertex3f;
import static org.lwjgl.opengl.GL20.glVertexAttrib2f;
import static xyz.valnet.engine.util.Math.lerp;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.shaders.SimpleShader;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.interfaces.IHaulable;
import xyz.valnet.hadean.interfaces.IJob;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ITileThing;
import xyz.valnet.hadean.interfaces.IWorkable;
import xyz.valnet.hadean.gameobjects.Job.JobStep;
import xyz.valnet.hadean.gameobjects.worldobjects.agents.Agent;
import xyz.valnet.hadean.interfaces.IWorker;
import xyz.valnet.hadean.pathfinding.AStarPathfinder;
import xyz.valnet.hadean.pathfinding.IPathfinder;
import xyz.valnet.hadean.pathfinding.Node;
import xyz.valnet.hadean.pathfinding.Path;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
public class Pawn extends WorldObject implements ISelectable, IWorker {
public class Pawn extends Agent implements IWorker {
private static int count = 0;
private String name = "Pawn " + (++ count);
private JobBoard jobboard;
private IPathfinder pathfinder;
private IHaulable carrying = null;
private float counter = 0;
private Path path;
private final float invocationThreshold = 100 + (float)(Math.random() * 50);
private boolean debug = false;
private static int pawnCount = 0;
private String name = "Pawn " + (++ pawnCount);
@Override
public void start() {
super.start();
jobboard = get(JobBoard.class);
pathfinder = new AStarPathfinder(terrain);
x = 0.5f + (int) (Math.random() * Terrain.WORLD_SIZE);
y = 0.5f + (int) (Math.random() * Terrain.WORLD_SIZE);
}
@Override
public void selectedRender() {
if(path != null) {
for(Node node : path) {
glBegin(GL_LINES);
Vector2f u, v;
if(node.from == null) u = camera.world2screen(x, y);
else u = camera.world2screen(node.from.x + 0.5f, node.from.y + 0.5f);
v = camera.world2screen(node.x + 0.5f, node.y + 0.5f);
glVertexAttrib2f(SimpleShader.TEX_COORD, 0, 88 / 256f);
glVertex3f(u.x, u.y, 3f);
glVertexAttrib2f(SimpleShader.TEX_COORD, 0, 88 / 255f);
glVertex3f(v.x, v.y, 3f);
glEnd();
}
}
x = (int) (Math.random() * Terrain.WORLD_SIZE);
y = (int) (Math.random() * Terrain.WORLD_SIZE);
}
@Override
public void render() {
if(path != null && !path.isComplete()) {
Node next = path.peek();
float t = counter / invocationThreshold;
camera.draw(Layers.PAWNS, Assets.pawn, lerp(x - 0.5f, next.x, t), lerp(y - 0.5f, next.y, t));
if(path != null && debug) {
for(Node node : path) {
glBegin(GL_LINES);
Vector2f u, v;
if(node.from == null) u = camera.world2screen(x, y);
else u = camera.world2screen(node.from.x + 0.5f, node.from.y + 0.5f);
v = camera.world2screen(node.x + 0.5f, node.y + 0.5f);
glVertexAttrib2f(SimpleShader.TEX_COORD, 0, 88 / 256f);
glVertex3f(u.x, u.y, 3f);
glVertexAttrib2f(SimpleShader.TEX_COORD, 0, 88 / 255f);
glVertex3f(v.x, v.y, 3f);
glEnd();
}
}
} else {
camera.draw(Layers.PAWNS, Assets.pawn, x - 0.5f, y - 0.5f);
}
// Drawing.setLayer(0.1f);
// Assets.flat.pushColor(Vector4f.black);
// Drawing.drawSprite(Assets.pawn, (int)(Terrain.left + dx * Terrain.TILE_SIZE) - Assets.pawn.width / 2, (int)(Terrain.top + dy * Terrain.TILE_SIZE) - Assets.pawn.height / 2);
// Assets.flat.swapColor(new Vector4f(1, 0, 0, 1));
// Drawing.setLayer(0.05f);
// Assets.flat.popColor();
super.render();
camera.draw(Layers.PAWNS, Assets.pawn, x, y);
}
@Override
public void update(float dTime) {
IJob currentJob = jobboard.getJob(this);
// cleanup current job...
if(currentJob != null && !currentJob.hasWork()) {
currentJob = null;
}
// if you dont have a job
if(currentJob == null && carrying == null) {
// and its a frame to try and get one...
if(counter == 0) {
tryStartWork();
currentJob = jobboard.getJob(this);
}
// if we still dont have a job, try path to wander.
if(currentJob == null && (path == null || path.isComplete())) {
newPath();
return;
}
// TODO possibly take care of needs here idk
}
if(path != null && !path.isComplete()) {
move();
return;
}
// try to do your work!
if(currentJob != null && currentJob.hasWork()) {
if(getCurrentPos().isOneOf(currentJob.getWorkablePositions())) {
if(currentJob instanceof IWorkable) {
((IWorkable)currentJob).doWork();
} else if (currentJob instanceof IHaulable) {
if(carrying == null) {
IHaulable thing = (IHaulable) currentJob;
Log log = thing.take();
carrying = log;
Vector2i dst = thing.getDestination().getCoords();
path = pathfinder.getPath((int)x, (int)y, dst.x, dst.y);
}
}
return;
}
} else if (carrying != null) {
// if we're at our destination, or if for some reason we just like
// didnt make it? but our path is so totally completed...
if(carrying.getDestination() == this.getTile() || path == null || path.isComplete()) {
this.getTile().placeThing((ITileThing) carrying);
carrying = null;
}
}
}
private Vector2i getCurrentPos() {
return new Vector2i((int)Math.floor(x), (int)Math.floor(y));
}
private void tryStartWork() {
jobboard.requestJob(this);
}
private void newPath() {
// set new destination
int randomX = (int)Math.floor(Math.random() * Terrain.WORLD_SIZE);
int randomY = (int)Math.floor(Math.random() * Terrain.WORLD_SIZE);
path = pathfinder.getPath((int)x, (int)y, randomX, randomY);
// // and route there.
// reroute();
}
private void reroute() {
// intify all the coordinates
int ix = (int)Math.floor(x);
int iy = (int)Math.floor(y);
int idx = path.dst.x;
int idy = path.dst.y;
// try to make a new path.
path = pathfinder.getPath(ix, iy, idx, idy);
}
private boolean paused = false;
private void move() {
if(paused) {
counter --;
if(counter < 0) counter = 0;
return;
}
// check if we CAN move.
Node nextNode = path.peek();
Tile nextTile = terrain.getTile(nextNode.x, nextNode.y);
if(!nextTile.isWalkable()) {
if(counter > 0) counter --;
if(counter < 0) counter = 0;
if(counter == 0) {
reroute();
}
return;
}
counter ++;
if(counter < invocationThreshold) return;
path.pop();
x = nextNode.x + 0.5f;
y = nextNode.y + 0.5f;
counter = 0;
}
@Override
public Vector4f getWorldBox() {
if(path != null && !path.isComplete()) {
float t = counter / invocationThreshold;
Node n = path.peek();
float x1 = lerp(x - 0.5f, n.x, t);
float y1 = lerp(y - 0.5f, n.y, t);
return new Vector4f(x1, y1, x1 + 1, y1 + 1);
} else {
return new Vector4f(x - 0.5f, y - 0.5f, x + 0.5f, y + 0.5f);
}
}
private static final Action ACTION_REROUTE = new Action("Re-route");
private static final Action ACTION_TOGGLE_DEBUG = new Action("Toggle\nDebug");
private static final Action ACTION_PAUSE = new Action("Pause");
@Override
public Action[] getActions() {
return new Action[] {
// ACTION_REROUTE,
ACTION_TOGGLE_DEBUG,
ACTION_PAUSE
};
}
@Override
public void runAction(Action action) {
if(action == ACTION_PAUSE) {
paused = !paused;
} else if(action == ACTION_REROUTE) {
reroute();
} else if(action == ACTION_TOGGLE_DEBUG) {
debug = !debug;
}
}
private String getCarriedName() {
if(carrying == null) return "Nothing";
String[] names = carrying.getClass().getName().split("\\.");
return names[names.length - 1];
}
public void runAction(Action action) {}
@Override
public String details() {
IJob currentJob = jobboard.getJob(this);
String jobString = currentJob == null ? "No Job" : currentJob.getJobName();
return "" + name + "\n" +
"Held | " + getCarriedName() + "\n" +
"Job | " + jobString + "\n" +
"";
return "";
}
@Override
public Vector2f getLocation() {
public Vector2f getWorldPosition() {
return new Vector2f(x, y);
}
@Override
public IPathfinder getPathfinder() {
return pathfinder;
}
@Override
public void setPath(Path path) {
this.path = path;
}
@Override
public String getName() {
return name;
}
@Override
public Vector4f getWorldBox() {
return new Vector4f(x, y, x + 1, y + 1);
}
private JobBoard jobboard;
@Override
protected void think() {
super.think();
// if we dont have a job
if(!jobboard.workerHasJob(this)) {
jobboard.requestJob(this); // try to get one
}
// if we have a job and need to go to it and we're not pathing to it
if(jobboard.workerHasJob(this) && !isAtJobStepLocation() && !isPathingToJobLocation()) {
goToJobStepLocation(); // start pathing there.
return; // and dont think about anything else.
}
// if we still dont have a job and we're not moving around
if(!jobboard.workerHasJob(this) && !isPathing()) {
if(Math.random() > 0.001f) wander(); // have a chance of wandering!
return; // and dont think about anything else.
}
}
private boolean isPathingToJobLocation() {
if(!isPathing()) return false;
return getDestination().equals(jobboard.getJob(this).getCurrentStep().getLocation().asInt());
}
private boolean isAtJobStepLocation() {
return jobboard.getJob(this).getCurrentStep().getLocation().equals(this.getWorldPosition());
}
private void goToJobStepLocation() {
goTo(jobboard
.getJob(this)
.getCurrentStep()
.getLocation()
.asInt()
);
}
// TODO at some point rewrite this to use an actor component array
// where we loop through until something _does_ sometihng.
@Override
protected boolean act() {
if(super.act()) return true;
if(doJob()) return true;
return false;
}
private boolean doJob() {
if(!jobboard.workerHasJob(this)) return false;
JobStep step = jobboard.getJob(this).getCurrentStep();
if(!getWorldPosition().asInt().equals(step.getLocation().asInt())) return false;
if(step instanceof Job.Work) {
Job.Work workStep = (Job.Work)step;
if(workStep.doWork()) step.next();
return true;
}
return false;
}
}

View File

@ -81,42 +81,9 @@ public class Rice extends WorldObject implements ITileThing, ISelectable {
return "Bag of Rice";
}
// @Override
// public boolean hasWork() {
// return haul.value();
// }
// @Override
// public Vector2i[] getWorablePositions() {
// return new Vector2i[] {
// new Vector2i((int)x + 1, (int)y),
// new Vector2i((int)x - 1, (int)y),
// new Vector2i((int)x, (int)y + 1),
// new Vector2i((int)x, (int)y - 1)
// };
// }
// @Override
// public Vector2i getLocation() {
// return new Vector2i((int)x, (int)y);
// }
// @Override
// public Log take() {
// haul.set(false);
// Tile tile = terrain.getTile((int)x, (int)y);
// tile.remove(this);
// return this;
// }
// @Override
// public Tile getDestination() {
// return get(Stockpile.class).getTile();
// }
// @Override
// public String getJobName() {
// return "Haul Log";
// }
@Override
public String getName() {
return "Rice";
}
}

View File

@ -1,21 +1,16 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.interfaces.BuildableMetadata;
import xyz.valnet.hadean.interfaces.IBuildable;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ITileThing;
import xyz.valnet.hadean.interfaces.IWorkable;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
@BuildableMetadata(category = "Zones", name = "Stockpile")
public class Stockpile extends WorldObject implements IWorkable, ISelectable, ITileThing, IBuildable {
private JobBoard board;
public class Stockpile extends WorldObject implements ISelectable, ITileThing, IBuildable {
private int w, h;
@ -40,33 +35,6 @@ public class Stockpile extends WorldObject implements IWorkable, ISelectable, IT
@Override
public void start() {
super.start();
board = get(JobBoard.class);
board.postJob(this);
}
@Override
public boolean hasWork() {
return false;
}
@Override
public Vector2i[] getWorkablePositions() {
return new Vector2i[] {
new Vector2i((int) x, (int) y + 1),
new Vector2i((int) x, (int) y - 1),
new Vector2i((int) x + 1, (int) y),
new Vector2i((int) x - 1, (int) y)
};
}
@Override
public Vector2i getLocation() {
return new Vector2i((int) x, (int) y);
}
@Override
public String getJobName() {
return "No jobs here!";
}
@Override
@ -96,11 +64,6 @@ public class Stockpile extends WorldObject implements IWorkable, ISelectable, IT
return "";
}
@Override
public void doWork() {
}
@Override
public boolean isWalkable() {
return true;
@ -133,4 +96,10 @@ public class Stockpile extends WorldObject implements IWorkable, ISelectable, IT
}
}
@Override
public String getName() {
// TODO Auto-generated method stub
return "Stockpile";
}
}

View File

@ -2,6 +2,7 @@ package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.Job;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.interfaces.ISelectable;
import xyz.valnet.hadean.interfaces.ITileThing;
@ -15,7 +16,7 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
private static int counter = 0;
private String name = "Tree " + (++ counter);
private boolean chopFlag = false;
private Job chopJob = null;
private int x, y;
@ -29,7 +30,7 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
Assets.flat.pushColor(new Vector4f(1 - getProgress(), 1 - getProgress(), 1 - getProgress(), 1.0f));
camera.draw(Layers.AIR, Assets.tree, x - 1, y - 2, 3, 3);
Assets.flat.popColor();
if(hasWork()) {
if(chopJob != null) {
camera.draw(Layers.MARKERS, Assets.lilAxe, x, y);
}
}
@ -56,20 +57,15 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
@Override
public void runAction(Action action) {
if(action == ACTION_CHOP) {
chopFlag = !chopFlag;
if(chopFlag) {
get(JobBoard.class).postJob(this);
if(chopJob == null) {
chopJob = get(JobBoard.class).postSimpleWorkJob("Chop Tree", this);
} else {
get(JobBoard.class).rescindJob(this);
get(JobBoard.class).rescindJob(chopJob);
chopJob = null;
}
}
}
@Override
public boolean hasWork() {
return chopFlag && choppage < strength;
}
@Override
public Vector2i[] getWorkablePositions() {
return new Vector2i[] {
@ -88,14 +84,15 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
}
@Override
public void doWork() {
public boolean doWork() {
choppage ++;
return getProgress() >= 1;
}
@Override
public String details() {
return "" + name + "\n" +
"Chop Flag | " + chopFlag + "\n" +
"Chop Flag | " + (chopJob != null) + "\n" +
"Progress | " + (String.format("%.2f", getProgress() * 100)) + "%";
}
@ -122,13 +119,13 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka
add(new Log(x, y));
}
@Override
public Vector2i getLocation() {
return new Vector2i(x, y);
}
@Override
public String getJobName() {
return "Chop " + name;
}
@Override
public String getName() {
return "Tree";
}
}

View File

@ -1,11 +1,13 @@
package xyz.valnet.hadean.gameobjects.worldobjects;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.scenegraph.GameObject;
import xyz.valnet.hadean.gameobjects.Camera;
import xyz.valnet.hadean.gameobjects.Terrain;
import xyz.valnet.hadean.gameobjects.Tile;
public class WorldObject extends GameObject {
public abstract class WorldObject extends GameObject {
protected float x;
protected float y;
@ -23,4 +25,11 @@ public class WorldObject extends GameObject {
return terrain.getTile((int)x, (int)y);
}
public Vector2f getWorldPosition() {
return new Vector2f(x, y);
}
public abstract String getName();
public abstract Vector4f getWorldBox();
}

View File

@ -0,0 +1,149 @@
package xyz.valnet.hadean.gameobjects.worldobjects.agents;
import static org.lwjgl.opengl.GL11.GL_LINES;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glVertex3f;
import static org.lwjgl.opengl.GL20.glVertexAttrib2f;
import xyz.valnet.engine.graphics.Drawing;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.engine.math.Vector2i;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.engine.shaders.SimpleShader;
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;
import xyz.valnet.hadean.pathfinding.IPathfinder;
import xyz.valnet.hadean.pathfinding.Node;
import xyz.valnet.hadean.pathfinding.Path;
import xyz.valnet.hadean.util.Action;
import xyz.valnet.hadean.util.Assets;
import xyz.valnet.hadean.util.Layers;
public abstract class Agent extends WorldObject implements ISelectable {
public abstract String getName();
private int frameCounter = 0;
private int speed = 100 + (int)(Math.random() * 50);
private IPathfinder pathfinder;
private Path path = null;
protected boolean isPathing() {
return path != null && !path.isComplete();
}
@Override
public void start() {
super.start();
frameCounter = speed;
pathfinder = new AStarPathfinder(terrain);
}
@Override
public void update(float dTime) {
think();
act();
}
private void move() {
frameCounter++;
if(frameCounter >= speed) {
Vector2i nextPos = path.pop().getPosition();
this.x = nextPos.x;
this.y = nextPos.y;
if(path.isComplete()) path = null;
frameCounter = 0;
}
}
private void correctPath() {
if(path != null && path.isComplete()) path = null;
if(path == null) return;
Tile nextTile = terrain.getTile(path.peek().getPosition());
if(!nextTile.isWalkable()) {
path = pathfinder.getPath(
(int)Math.floor(x),
(int)Math.floor(y),
path.dst.x,
path.dst.y
);
}
}
protected void think() {
correctPath();
}
protected boolean act() {
if(path != null) {
move();
return true;
}
return false;
}
protected void goTo(int x, int y) {
if(x == (int) this.x && y == (int) this.y) return;
frameCounter = 0;
path = pathfinder.getPath((int)this.x, (int)this.y, x, y);
}
protected void goTo(Vector2i location) {
goTo(location.x, location.y);
}
protected void wander() {
System.out.println("WANDER!");
int randomX = (int)Math.floor(Math.random() * Terrain.WORLD_SIZE);
int randomY = (int)Math.floor(Math.random() * Terrain.WORLD_SIZE);
path = pathfinder.getPath((int)x, (int)y, randomX, randomY);
}
@Override
public void renderAlpha() {
Drawing.setLayer(Layers.GENERAL_UI);
Assets.flat.pushColor(Vector4f.opacity(0.4f));
if(path != null) {
for(Node node : path) {
glBegin(GL_LINES);
Vector2f u, v;
if(node.from == null) u = camera.world2screen(x, y);
else u = camera.world2screen(node.from.x + 0.5f, node.from.y + 0.5f);
v = camera.world2screen(node.x + 0.5f, node.y + 0.5f);
glVertexAttrib2f(SimpleShader.TEX_COORD, 0, 88 / 256f);
glVertex3f(u.x, u.y, 3f);
glVertexAttrib2f(SimpleShader.TEX_COORD, 0, 88 / 255f);
glVertex3f(v.x, v.y, 3f);
glEnd();
}
Assets.flat.swapColor(Vector4f.opacity(0.6f));
Assets.selectionFrame.draw(
camera.world2Screen(
terrain.getTile(
path.getDestination().getPosition()
)
.getWorldBox()
)
.toXYWH()
);
}
Assets.flat.popColor();
}
@Override
public Action[] getActions() {
return new Action[0];
}
protected Vector2i getDestination() {
if(path == null) return null;
return path.getDestination().getPosition();
}
}

View File

@ -0,0 +1,41 @@
package xyz.valnet.hadean.gameobjects.worldobjects.items;
import xyz.valnet.engine.math.Vector4f;
import xyz.valnet.hadean.gameobjects.JobBoard;
import xyz.valnet.hadean.gameobjects.worldobjects.WorldObject;
import xyz.valnet.hadean.util.SmartBoolean;
public class Item extends WorldObject {
protected JobBoard jobboard;
private SmartBoolean haul;
// camera.draw(Layers.MARKERS, Assets.haulArrow, x, y);
@Override
public void start() {
super.start();
haul = new SmartBoolean(false, new SmartBoolean.IListener() {
@Override
public void rise() {
}
@Override
public void fall() {
}
});
}
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
@Override
public Vector4f getWorldBox() {
return null;
}
}

View File

@ -2,6 +2,6 @@ package xyz.valnet.hadean.interfaces;
public interface IBuildLayerListener {
public void update(int x, int y, int w, int h);
public void select(int x, int y, int w, int h);
public void build(int x, int y, int w, int h);
public void cancel();
}

View File

@ -1,9 +0,0 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.hadean.gameobjects.Tile;
import xyz.valnet.hadean.gameobjects.worldobjects.Log;
public interface IHaulable extends IJob {
public Log take();
public Tile getDestination();
}

View File

@ -1,12 +0,0 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.engine.math.Vector2i;
public interface IJob {
public boolean hasWork();
public Vector2i[] getWorkablePositions();
@Deprecated // please use the workable positions.
public Vector2i getLocation();
public String getJobName();
}

View File

@ -1,5 +1,9 @@
package xyz.valnet.hadean.interfaces;
public interface IWorkable extends IJob {
public void doWork();
import xyz.valnet.engine.math.Vector2i;
public interface IWorkable {
public boolean doWork();
public Vector2i[] getWorkablePositions();
public String getJobName();
}

View File

@ -1,12 +1,8 @@
package xyz.valnet.hadean.interfaces;
import xyz.valnet.engine.math.Vector2f;
import xyz.valnet.hadean.pathfinding.IPathfinder;
import xyz.valnet.hadean.pathfinding.Path;
public interface IWorker {
public Vector2f getLocation();
public IPathfinder getPathfinder();
public void setPath(Path path);
public Vector2f getWorldPosition();
public String getName();
}

View File

@ -64,6 +64,9 @@ public class AStarPathfinder implements IPathfinder {
}
public Path getPath(int x1, int y1, int x2, int y2) {
if(x1 == x2 && y1 == y2) return null;
List<Node> open = new ArrayList<Node>();
List<Node> closed = new ArrayList<Node>();

View File

@ -1,5 +1,7 @@
package xyz.valnet.hadean.pathfinding;
import xyz.valnet.engine.math.Vector2i;
public class Node {
public int x, y, g, h;
public Node from;
@ -7,4 +9,8 @@ public class Node {
public int getCost() {
return g + h;
}
public Vector2i getPosition() {
return new Vector2i(x, y);
}
}

View File

@ -22,6 +22,10 @@ public class Path implements Iterable<Node> {
return nodes.pop();
}
public Node getDestination() {
return nodes.firstElement();
}
public boolean isComplete() {
return nodes.isEmpty();
}

View File

@ -7,10 +7,11 @@ 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.Selection;
import xyz.valnet.hadean.gameobjects.tabs.BuildTab;
import xyz.valnet.hadean.gameobjects.tabs.JobBoardTab;
import xyz.valnet.hadean.gameobjects.tabs.MenuTab;
import xyz.valnet.hadean.gameobjects.inputlayer.SelectionLayer;
import xyz.valnet.hadean.gameobjects.ui.HoverQuery;
import xyz.valnet.hadean.gameobjects.ui.tabs.BuildTab;
import xyz.valnet.hadean.gameobjects.ui.tabs.JobBoardTab;
import xyz.valnet.hadean.gameobjects.ui.tabs.MenuTab;
import xyz.valnet.hadean.gameobjects.worldobjects.Pawn;
// TODO BIG IDEAS
@ -35,7 +36,7 @@ public class GameScene extends SceneGraph {
objects.add(new Pawn());
}
objects.add(new Selection());
objects.add(new SelectionLayer());
objects.add(new SelectionUI());
objects.add(new BuildLayer());
@ -44,6 +45,7 @@ public class GameScene extends SceneGraph {
objects.add(new BuildTab());
objects.add(new JobBoardTab());
objects.add(new MenuTab());
objects.add(new HoverQuery());
}
}