diff --git a/idea.md b/idea.md index 1a4a34a..4841e39 100644 --- a/idea.md +++ b/idea.md @@ -21,14 +21,33 @@ worker knows it can move on to another action. A Worker may also tell a job board, that it no longer wishes to do work, and the job will be released. -# IMouseCaptureArea - -its just a name, but reframe current mouse shit to it. - -# Create class for x/y positioned things. - -can be STUPID SIMPLE TO START - # Convert ITileThing to class -getTile() needs to be a common method. \ No newline at end of file +Think about these words and what they mean + +Tile +TileThing +Entity +Item + +# Mouse up / down bubbling + +the events should still go through all layers, +and be allowed to be handled by any layer, if +that layer syas its handled. + +problem: unknown operating order of right click +opening / closing the build panel. and its state +is controlled from 2 places. + +the build layer can cancel and cause the panel +to close, but also the tab should be able to hook +into global mouse events for re-opening the panel. + +opening has to be done from the build tab, because +it is the thing that activates the build layer. + +consequence is that without proper care a single +event could immediately open & close the panel in +the same frame. so, the event should be able to +be captured and cease propogation. \ No newline at end of file diff --git a/src/main/java/xyz/valnet/engine/App.java b/src/main/java/xyz/valnet/engine/App.java index 2dae3ff..009f3bf 100644 --- a/src/main/java/xyz/valnet/engine/App.java +++ b/src/main/java/xyz/valnet/engine/App.java @@ -130,7 +130,7 @@ public class App { GL.createCapabilities(); - glClearColor(0.3f, 0.3f, 0.3f, 1.0f); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); diff --git a/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java b/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java index 3769ad2..7d74cf0 100644 --- a/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java +++ b/src/main/java/xyz/valnet/engine/scenegraph/IMouseCaptureArea.java @@ -5,7 +5,7 @@ import xyz.valnet.engine.math.Vector4f; public interface IMouseCaptureArea { public void mouseEnter(); public void mouseLeave(); - public boolean mouseDown(int button); + public void mouseDown(int button); public void mouseUp(int button); public Vector4f getBox(); diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/JobBoard.java b/src/main/java/xyz/valnet/hadean/gameobjects/JobBoard.java new file mode 100644 index 0000000..f959b33 --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/gameobjects/JobBoard.java @@ -0,0 +1,138 @@ +package xyz.valnet.hadean.gameobjects; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +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.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 availableJobs = new HashSet(); + private Map allocations = new HashMap(); + + public void postJob(IJob job) { + availableJobs.add(job); + } + + public void rescindJob(IJob job) { + if(allocations.values().contains(job)) { + List toFire = new ArrayList(); + + for(IWorker worker : allocations.keySet()) { + if(allocations.get(worker) == job) { + toFire.add(worker); + } + } + + for(IWorker worker : toFire) { + allocations.remove(worker); + } + } + + if(availableJobs.contains(job)) { + availableJobs.remove(job); + } + } + + public void requestJob(IWorker worker) { + // TODO worker has capabilities? + Vector2f workerLocation = worker.getLocation(); + IPathfinder pathfinder = worker.getPathfinder(); + + List 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( + workable, + workable.getLocation().distanceTo( + (int) workerLocation.x, + (int) workerLocation.y + ) + )) + // sort the jobs by their distance from the worker + .sorted(new Comparator>() { + @Override + public int compare(Pair a, Pair b) { + if(a.second() > b.second()) return 1; + if(b.second() > a.second()) return -1; + return 0; + } + }) + // then convert the stream back to just the jobs + .map(workerDistanceTuple -> workerDistanceTuple.first()) + .toList(); + + + if(workables.size() > 0) { + for(IJob job : workables) { + if(!job.hasWork()) continue; + Vector2i[] workablePositions = job.getWorablePositions(); + 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; + } + } + } + + @Override + public void update(float dTime) { + List toRemove = new ArrayList(); + for(IJob job : allocations.values()) { + if(!job.hasWork()) { + toRemove.add(job); + } + } + for(IJob job : toRemove) { + rescindJob(job); + } + } + + public IJob getJob(IWorker worker) { + if(allocations.containsKey(worker)) { + return allocations.get(worker); + } else return null; + } + + public String details() { + + String takenJobsString = ""; + String availableJobsString = ""; + + for(Entry allocation : allocations.entrySet()) { + takenJobsString += " " + allocation.getKey().getName() + ": " + allocation.getValue().getName() + "\n"; + } + + for(IJob job : availableJobs) { + availableJobsString += " " + job.getName() + "\n"; + } + + return "Available Jobs: " + availableJobs.size() + "\n" + availableJobsString + + "Taken Jobs: " + allocations.size() + "\n" + takenJobsString; + } + +} diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java b/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java index f3209d1..b80efe9 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/SelectionUI.java @@ -7,6 +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.input.Button; import xyz.valnet.hadean.input.IButtonListener; import xyz.valnet.hadean.input.SimpleButton; @@ -181,8 +182,8 @@ public class SelectionUI extends GameObject implements ISelectionChangeListener, } @Override - public boolean mouseDown(int button) { - return false; + public void mouseDown(int button) { + return; } @Override diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/Terrain.java b/src/main/java/xyz/valnet/hadean/gameobjects/Terrain.java index fd42da6..fa3d17c 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/Terrain.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/Terrain.java @@ -23,10 +23,10 @@ public class Terrain extends GameObject implements IPathable { } } - Tile randomTile = getRandomTile(); - Vector2i coords = randomTile.getCoords(); - Stockpile stockpile = new Stockpile(coords.x, coords.y); - randomTile.placeThing(stockpile); + // Tile randomTile = getRandomTile(); + // Vector2i coords = randomTile.getCoords(); + // Stockpile stockpile = new Stockpile(coords.x, coords.y); + // randomTile.placeThing(stockpile); camera = get(Camera.class); camera.focus(WORLD_SIZE / 2, WORLD_SIZE / 2); diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/Tile.java b/src/main/java/xyz/valnet/hadean/gameobjects/Tile.java index d645b29..7810786 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/Tile.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/Tile.java @@ -37,17 +37,17 @@ public class Tile extends GameObject { public void start() { camera = get(Camera.class); - if(Math.random() > 0.99) { + if(Math.random() > 0.97) { Tree tree = new Tree(x, y); stuff.add(tree); add(tree); } - if(Math.random() > 0.98) { - Log log = new Log(x, y); - stuff.add(log); - add(log); - } + // if(Math.random() > 0.98) { + // Log log = new Log(x, y); + // stuff.add(log); + // add(log); + // } } public void placeThing(ITileThing thing) { diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/BuildLayer.java b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/BuildLayer.java new file mode 100644 index 0000000..00d90fa --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/BuildLayer.java @@ -0,0 +1,102 @@ +package xyz.valnet.hadean.gameobjects.inputlayer; + +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.engine.scenegraph.IMouseCaptureArea; +import xyz.valnet.hadean.gameobjects.Camera; +import xyz.valnet.hadean.interfaces.IBuildLayerListener; +import xyz.valnet.hadean.util.Layers; + +public class BuildLayer extends GameObject implements IMouseCaptureArea { + + private Camera camera; + + private boolean active = false; + + private IBuildLayerListener listener = null; + + @Override + public void start() { + camera = get(Camera.class); + } + + @Override + public void update(float dTime) { + if(listener == null) return; + broadcastWorldCoords(); + } + + public void activate(IBuildLayerListener listener) { + active = true; + this.listener = listener; + broadcastWorldCoords(); + } + + private void broadcastWorldCoords() { + Vector2f worldcoords = camera.screen2world(App.mouseX, App.mouseY); + listener.update(worldcoords.x, worldcoords.y, 1, 1); + } + + public void deactiveate() { + active = false; + this.listener = null; + } + + @Override + public void mouseEnter() { + // TODO Auto-generated method stub + + } + + @Override + public void mouseLeave() { + // TODO Auto-generated method stub + + } + + private float x, y; + private boolean mouseDown = false; + + @Override + public void mouseDown(int button) { + if(button == 1 && active) { + listener.cancel(); + deactiveate(); + } else if(button == 0 && active) { + Vector2f worldcoords = camera.screen2world(App.mouseX, App.mouseY); + mouseDown = true; + x = worldcoords.x; + y = worldcoords.y; + } + } + + @Override + public void mouseUp(int button) { + if(button == 0 && active && mouseDown) { + Vector2f worldcoords = camera.screen2world(App.mouseX, App.mouseY); + mouseDown = false; + float x1 = x; + float y1 = y; + float x2 = worldcoords.x; + float y2 = worldcoords.y; + float minX = Math.min(x1, x2); + float minY = Math.min(y1, y2); + float maxX = Math.max(x1, x2); + float maxY = Math.max(y1, y2); + listener.select(minX, minY, maxX, maxY); + } + } + + @Override + public Vector4f getBox() { + return active ? new Vector4f(0, 0, 1024, 576) : Vector4f.zero; + } + + @Override + public int getLayer() { + return Layers.BUILD_INTERACTABLE; + } + +} diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/Selection.java b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/Selection.java similarity index 97% rename from src/main/java/xyz/valnet/hadean/gameobjects/Selection.java rename to src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/Selection.java index 5ac3db1..6fa50d2 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/Selection.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/inputlayer/Selection.java @@ -1,4 +1,4 @@ -package xyz.valnet.hadean.gameobjects; +package xyz.valnet.hadean.gameobjects.inputlayer; import java.util.ArrayList; import java.util.List; @@ -9,6 +9,7 @@ import xyz.valnet.engine.math.Vector2f; 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.ISelectable; import xyz.valnet.hadean.interfaces.ISelectionChangeListener; import xyz.valnet.hadean.util.Assets; @@ -170,14 +171,14 @@ public class Selection extends GameObject implements IMouseCaptureArea { } @Override - public boolean mouseDown(int button) { - if(!active) return false; + public void mouseDown(int button) { + if(!active) return; + if(button == 0) { if(initialCoords == null) { initialCoords = new Vector2f(App.mouseX, App.mouseY); } } - return false; } @Override diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/tabs/ArchitectTab.java b/src/main/java/xyz/valnet/hadean/gameobjects/tabs/ArchitectTab.java deleted file mode 100644 index b2b082a..0000000 --- a/src/main/java/xyz/valnet/hadean/gameobjects/tabs/ArchitectTab.java +++ /dev/null @@ -1,68 +0,0 @@ -package xyz.valnet.hadean.gameobjects.tabs; - -import java.util.ArrayList; -import java.util.List; - -import xyz.valnet.hadean.gameobjects.BottomBar; -import xyz.valnet.hadean.gameobjects.Selection; -import xyz.valnet.hadean.interfaces.ISelectable; -import xyz.valnet.hadean.interfaces.ISelectionChangeListener; -import xyz.valnet.hadean.util.Assets; - -import static xyz.valnet.engine.util.Math.lerp; - -public class ArchitectTab extends Tab implements ISelectionChangeListener { - - private Selection selection; - - private boolean opened = false; - private float progress = 0f; - private float width = 200; - - private int padding = 10; - - private float toRange(float n, float a, float b) { - float l = b - a; - float p = n * l; - return a + p; - } - - @Override - public void render() { - float x = toRange(progress, -width - padding, padding); - Assets.uiFrame.draw((int) x, padding, (int) width, 576 - padding * 2 - BottomBar.bottomBarHeight); - } - - @Override - public void start() { - super.start(); - selection = get(Selection.class); - if(selection != null) { - selection.subscribe(this); - } - } - - @Override - public void update(float dTime) { - progress = lerp(progress, opened ? 1 : 0, 0.05f); - } - - @Override - public void selectionChanged(List selected) { - if(selected.isEmpty()) return; - opened = false; - } - - @Override - public void evoke() { - opened = !opened; - if(opened) { - selection.updateSelection(new ArrayList()); - } - } - - @Override - public String getTabName() { - return "Build"; - } -} diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/tabs/BuildTab.java b/src/main/java/xyz/valnet/hadean/gameobjects/tabs/BuildTab.java new file mode 100644 index 0000000..6819580 --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/gameobjects/tabs/BuildTab.java @@ -0,0 +1,127 @@ +package xyz.valnet.hadean.gameobjects.tabs; + +import static xyz.valnet.engine.util.Math.lerp; + +import java.util.ArrayList; +import java.util.List; + +import xyz.valnet.engine.graphics.Drawing; +import xyz.valnet.engine.math.Vector4f; +import xyz.valnet.hadean.gameobjects.BottomBar; +import xyz.valnet.hadean.gameobjects.Camera; +import xyz.valnet.hadean.gameobjects.Stockpile; +import xyz.valnet.hadean.gameobjects.Terrain; +import xyz.valnet.hadean.gameobjects.inputlayer.BuildLayer; +import xyz.valnet.hadean.gameobjects.inputlayer.Selection; +import xyz.valnet.hadean.interfaces.IBuildLayerListener; +import xyz.valnet.hadean.interfaces.ISelectable; +import xyz.valnet.hadean.interfaces.ISelectionChangeListener; +import xyz.valnet.hadean.interfaces.ITileThing; +import xyz.valnet.hadean.util.Assets; +import xyz.valnet.hadean.util.Layers; +import xyz.valnet.hadean.util.SmartBoolean; + +public class BuildTab extends Tab implements ISelectionChangeListener { + + private Selection selection; + private BuildLayer buildLayer; + private Camera camera; + private Terrain terrain; + + private SmartBoolean opened; + private float progress = 0f; + private float width = 200; + + private int padding = 10; + + private int x, y; + + @Override + public void render() { + Drawing.setLayer(Layers.GENERAL_UI); + float left = lerp(-width - padding, padding, progress); + Assets.uiFrame.draw((int) left, padding, (int) width, 576 - padding * 2 - BottomBar.bottomBarHeight); + + if(opened.value()) { + Drawing.setLayer(Layers.BUILD_INTERACTABLE); + // draw the currently selected build item + Assets.flat.pushColor(new Vector4f(1f, 1f, 1f, 0.8f)); + camera.draw(Assets.stockpile, x, y); + Assets.flat.popColor(); + } + } + + @Override + public void start() { + super.start(); + buildLayer = get(BuildLayer.class); + selection = get(Selection.class); + camera = get(Camera.class); + terrain = get(Terrain.class); + + IBuildLayerListener buildListener = new IBuildLayerListener() { + @Override + public void update(float nx, float ny, float nw, float nh) { + x = (int)Math.floor(nx); + y = (int)Math.floor(ny); + } + + @Override + public void select(float nx, float ny, float nw, float nh) { + x = (int)Math.floor(nx); + y = (int)Math.floor(ny); + ITileThing stockpile = new Stockpile(x, y); + terrain.getTile(x, y).placeThing(stockpile); + opened.set(false); + } + + @Override + public void cancel() { + opened.set(false); + } + }; + + opened = new SmartBoolean(false, new SmartBoolean.IListener() { + + @Override + public void rise() { + buildLayer.activate(buildListener); + } + + @Override + public void fall() { + buildLayer.deactiveate(); + } + + }); + + if(selection != null) { + selection.subscribe(this); + } + } + + @Override + public void update(float dTime) { + progress = lerp(progress, opened.value() ? 1 : 0, 0.05f); + } + + @Override + public void selectionChanged(List selected) { + if(selected.isEmpty()) return; + opened.set(false); + } + + @Override + public void evoke() { + opened.toggle(); + + if(opened.value()) { + selection.updateSelection(new ArrayList()); + } + } + + @Override + public String getTabName() { + return "Build"; + } +} diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/tabs/JobBoardTab.java b/src/main/java/xyz/valnet/hadean/gameobjects/tabs/JobBoardTab.java new file mode 100644 index 0000000..bc1671a --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/gameobjects/tabs/JobBoardTab.java @@ -0,0 +1,80 @@ +package xyz.valnet.hadean.gameobjects.tabs; + +import static xyz.valnet.engine.util.Math.lerp; + +import java.util.ArrayList; +import java.util.List; + +import xyz.valnet.engine.graphics.Drawing; +import xyz.valnet.hadean.gameobjects.BottomBar; +import xyz.valnet.hadean.gameobjects.Camera; +import xyz.valnet.hadean.gameobjects.JobBoard; +import xyz.valnet.hadean.gameobjects.Terrain; +import xyz.valnet.hadean.gameobjects.inputlayer.BuildLayer; +import xyz.valnet.hadean.gameobjects.inputlayer.Selection; +import xyz.valnet.hadean.interfaces.ISelectable; +import xyz.valnet.hadean.interfaces.ISelectionChangeListener; +import xyz.valnet.hadean.util.Assets; +import xyz.valnet.hadean.util.Layers; +import xyz.valnet.hadean.util.SmartBoolean; + +public class JobBoardTab extends Tab implements ISelectionChangeListener { + + private Selection selection; + private JobBoard jobBoard; + + private SmartBoolean opened; + private float progress = 0f; + private float width = 200; + + private int padding = 10; + + private int x, y; + + @Override + public void render() { + Drawing.setLayer(Layers.GENERAL_UI); + float left = lerp(-width - padding, padding, progress); + Assets.uiFrame.draw((int) left, padding, (int) width, 576 - padding * 2 - BottomBar.bottomBarHeight); + Assets.font.drawString(jobBoard.details(), (int) left + padding, padding * 2); + } + + @Override + public void start() { + super.start(); + selection = get(Selection.class); + jobBoard = get(JobBoard.class); + + opened = new SmartBoolean(false, new SmartBoolean.IListener() { + }); + + if(selection != null) { + selection.subscribe(this); + } + } + + @Override + public void update(float dTime) { + progress = lerp(progress, opened.value() ? 1 : 0, 0.05f); + } + + @Override + public void selectionChanged(List selected) { + if(selected.isEmpty()) return; + opened.set(false); + } + + @Override + public void evoke() { + opened.toggle(); + + if(opened.value()) { + selection.updateSelection(new ArrayList()); + } + } + + @Override + public String getTabName() { + return "Jobs"; + } +} diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Log.java b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Log.java index 06dceaf..92eb232 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Log.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Log.java @@ -108,5 +108,10 @@ public class Log extends WorldObject implements ITileThing, ISelectable, IHaulab this.x = x; this.y = y; } + + @Override + public String getName() { + return "Haul Log"; + } } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Pawn.java b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Pawn.java index dbc0a06..d82b1bc 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Pawn.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Pawn.java @@ -7,15 +7,12 @@ import static org.lwjgl.opengl.GL11.glVertex3f; import static org.lwjgl.opengl.GL20.glVertexAttrib2f; import static xyz.valnet.engine.util.Math.lerp; -import java.util.Comparator; -import java.util.List; - 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.Camera; +import xyz.valnet.hadean.gameobjects.JobBoard; import xyz.valnet.hadean.gameobjects.Terrain; import xyz.valnet.hadean.gameobjects.Tile; import xyz.valnet.hadean.interfaces.IHaulable; @@ -23,6 +20,7 @@ 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.interfaces.IWorker; import xyz.valnet.hadean.pathfinding.AStarPathfinder; import xyz.valnet.hadean.pathfinding.IPathfinder; import xyz.valnet.hadean.pathfinding.Node; @@ -30,7 +28,13 @@ import xyz.valnet.hadean.pathfinding.Path; import xyz.valnet.hadean.util.Action; import xyz.valnet.hadean.util.Assets; -public class Pawn extends WorldObject implements ISelectable { +public class Pawn extends WorldObject implements ISelectable, IWorker { + + private static int count = 0; + private String name = "Pawn " + (++ count); + + private JobBoard jobboard; + private IPathfinder pathfinder; private IHaulable carrying = null; @@ -40,19 +44,15 @@ public class Pawn extends WorldObject implements ISelectable { private final float invocationThreshold = 100 + (float)(Math.random() * 50); - private Camera camera; - private Terrain terrain; - private IPathfinder pathfinder; - private boolean debug = false; @Override public void start() { - camera = get(Camera.class); - terrain = get(Terrain.class); + 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); + x = 0.5f + (int) (Math.random() * Terrain.WORLD_SIZE); + y = 0.5f + (int) (Math.random() * Terrain.WORLD_SIZE); } @Override @@ -118,6 +118,8 @@ public class Pawn extends WorldObject implements ISelectable { @Override public void update(float dTime) { + IJob currentJob = jobboard.getJob(this); + // cleanup current job... if(currentJob != null && !currentJob.hasWork()) { currentJob = null; @@ -128,6 +130,7 @@ public class Pawn extends WorldObject implements ISelectable { // 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. @@ -175,37 +178,8 @@ public class Pawn extends WorldObject implements ISelectable { return new Vector2i((int)Math.floor(x), (int)Math.floor(y)); } - private IJob currentJob; - private void tryStartWork() { - List workables = getAll(IJob.class) - .stream() - .filter(workable -> workable.hasWork()) - .sorted(new Comparator() { - @Override - public int compare(IJob a, IJob b) { - float distA = a.getLocation().distanceTo((int)x, (int)y); - float distB = b.getLocation().distanceTo((int)x, (int)y); - if(distA > distB) return -1; - if(distB > distA) return 1; - return 0; - } - }) - .toList(); - - if(workables.size() > 0) { - for(IJob job : workables) { - if(!job.hasWork()) continue; - Vector2i[] workablePositions = job.getWorablePositions(); - Path bestPathToJob = pathfinder.getBestPath( - new Vector2i((int)Math.floor(x), (int)Math.floor(y)), - workablePositions - ); - if(bestPathToJob == null) continue; - this.path = bestPathToJob; - currentJob = job; - } - } + jobboard.requestJob(this); } private void newPath() { @@ -304,7 +278,30 @@ public class Pawn extends WorldObject implements ISelectable { @Override public String details() { - return "Held | " + getCarriedName(); + return "" + name + "\n" + + "Held | " + getCarriedName() + "\n" + + "Job | " + jobboard.getJob(this).getName() + "\n" + + ""; + } + + @Override + public Vector2f getLocation() { + 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; } } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Tree.java b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Tree.java index c535f4b..7619ace 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Tree.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/Tree.java @@ -3,6 +3,7 @@ package xyz.valnet.hadean.gameobjects.worldobjects; import xyz.valnet.engine.graphics.Drawing; import xyz.valnet.engine.math.Vector2i; import xyz.valnet.engine.math.Vector4f; +import xyz.valnet.hadean.gameobjects.JobBoard; import xyz.valnet.hadean.interfaces.ISelectable; import xyz.valnet.hadean.interfaces.ITileThing; import xyz.valnet.hadean.interfaces.IWorkable; @@ -12,6 +13,9 @@ import xyz.valnet.hadean.util.Layers; public class Tree extends WorldObject implements ITileThing, ISelectable, IWorkable { + private static int counter = 0; + private String name = "Tree " + (++ counter); + private boolean chopFlag = false; private int x, y; @@ -56,6 +60,11 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka public void runAction(Action action) { if(action == ACTION_CHOP) { chopFlag = !chopFlag; + if(chopFlag) { + get(JobBoard.class).postJob(this); + } else { + get(JobBoard.class).rescindJob(this); + } } } @@ -75,7 +84,7 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka } protected float choppage = 0; - protected int strength = 5000; + protected int strength = 300; private float getProgress() { return (choppage / (float) strength); @@ -88,7 +97,8 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka @Override public String details() { - return "Chop Flag | " + chopFlag + "\n" + + return "" + name + "\n" + + "Chop Flag | " + chopFlag + "\n" + "Progress | " + (String.format("%.2f", getProgress() * 100)) + "%"; } @@ -125,4 +135,9 @@ public class Tree extends WorldObject implements ITileThing, ISelectable, IWorka this.x = x; this.y = y; } + + @Override + public String getName() { + return "Chop " + name; + } } diff --git a/src/main/java/xyz/valnet/hadean/input/Button.java b/src/main/java/xyz/valnet/hadean/input/Button.java index 5c1c423..aa57a4f 100644 --- a/src/main/java/xyz/valnet/hadean/input/Button.java +++ b/src/main/java/xyz/valnet/hadean/input/Button.java @@ -169,11 +169,10 @@ public class Button extends GameObject implements IMouseCaptureArea { } @Override - public boolean mouseDown(int button) { + public void mouseDown(int button) { if(button == 0) { mouseDown = true; } - return false; } @Override diff --git a/src/main/java/xyz/valnet/hadean/input/GOButton.java b/src/main/java/xyz/valnet/hadean/input/GOButton.java index 522784a..c9b58a3 100644 --- a/src/main/java/xyz/valnet/hadean/input/GOButton.java +++ b/src/main/java/xyz/valnet/hadean/input/GOButton.java @@ -42,8 +42,8 @@ public class GOButton extends GameObject implements IMouseCaptureArea { } @Override - public boolean mouseDown(int button) { - return false; + public void mouseDown(int button) { + } @Override diff --git a/src/main/java/xyz/valnet/hadean/interfaces/IBuildLayerListener.java b/src/main/java/xyz/valnet/hadean/interfaces/IBuildLayerListener.java new file mode 100644 index 0000000..2b50d5c --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/interfaces/IBuildLayerListener.java @@ -0,0 +1,7 @@ +package xyz.valnet.hadean.interfaces; + +public interface IBuildLayerListener { + public void update(float x, float y, float w, float h); + public void select(float x, float y, float w, float h); + public void cancel(); +} diff --git a/src/main/java/xyz/valnet/hadean/interfaces/IJob.java b/src/main/java/xyz/valnet/hadean/interfaces/IJob.java index 0c4c9d9..3692f9d 100644 --- a/src/main/java/xyz/valnet/hadean/interfaces/IJob.java +++ b/src/main/java/xyz/valnet/hadean/interfaces/IJob.java @@ -6,4 +6,5 @@ public interface IJob { public boolean hasWork(); public Vector2i[] getWorablePositions(); public Vector2i getLocation(); + public String getName(); } diff --git a/src/main/java/xyz/valnet/hadean/interfaces/IWorker.java b/src/main/java/xyz/valnet/hadean/interfaces/IWorker.java new file mode 100644 index 0000000..60010fa --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/interfaces/IWorker.java @@ -0,0 +1,12 @@ +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 String getName(); +} diff --git a/src/main/java/xyz/valnet/hadean/scenes/GameScene.java b/src/main/java/xyz/valnet/hadean/scenes/GameScene.java index 52de5b8..e424968 100644 --- a/src/main/java/xyz/valnet/hadean/scenes/GameScene.java +++ b/src/main/java/xyz/valnet/hadean/scenes/GameScene.java @@ -3,10 +3,13 @@ package xyz.valnet.hadean.scenes; import xyz.valnet.engine.scenegraph.SceneGraph; import xyz.valnet.hadean.gameobjects.BottomBar; import xyz.valnet.hadean.gameobjects.Camera; -import xyz.valnet.hadean.gameobjects.Selection; +import xyz.valnet.hadean.gameobjects.JobBoard; import xyz.valnet.hadean.gameobjects.SelectionUI; import xyz.valnet.hadean.gameobjects.Terrain; -import xyz.valnet.hadean.gameobjects.tabs.ArchitectTab; +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.worldobjects.Pawn; @@ -26,6 +29,7 @@ public class GameScene extends SceneGraph { objects.add(new Terrain()); objects.add(new Camera()); + objects.add(new JobBoard()); for(int i = 0; i < 5; i ++) { objects.add(new Pawn()); @@ -34,8 +38,11 @@ public class GameScene extends SceneGraph { objects.add(new Selection()); objects.add(new SelectionUI()); + objects.add(new BuildLayer()); + objects.add(new BottomBar()); - objects.add(new ArchitectTab()); + objects.add(new BuildTab()); + objects.add(new JobBoardTab()); objects.add(new MenuTab()); } diff --git a/src/main/java/xyz/valnet/hadean/util/Layers.java b/src/main/java/xyz/valnet/hadean/util/Layers.java index 56b16c4..a3fba22 100644 --- a/src/main/java/xyz/valnet/hadean/util/Layers.java +++ b/src/main/java/xyz/valnet/hadean/util/Layers.java @@ -13,6 +13,7 @@ public class Layers { public static final int MARKERS = current ++; public static final int SELECTION_IDENTIFIERS = current ++; public static final int AREA_SELECT_BOX = current ++; + public static final int BUILD_INTERACTABLE = current ++; public static final int GENERAL_UI = current ++; public static final int GENERAL_UI_INTERACTABLE = current ++; public static final int BOTTOM_BAR = current ++; diff --git a/src/main/java/xyz/valnet/hadean/util/Pair.java b/src/main/java/xyz/valnet/hadean/util/Pair.java new file mode 100644 index 0000000..5af330a --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/util/Pair.java @@ -0,0 +1,16 @@ +package xyz.valnet.hadean.util; + +public class Pair { + private final T t; + private final U u; + public Pair(T t, U u) { + this.t = t; + this.u = u; + } + public T first() { + return t; + } + public U second() { + return u; + } +} diff --git a/src/main/java/xyz/valnet/hadean/util/SmartBoolean.java b/src/main/java/xyz/valnet/hadean/util/SmartBoolean.java new file mode 100644 index 0000000..834be14 --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/util/SmartBoolean.java @@ -0,0 +1,39 @@ +package xyz.valnet.hadean.util; + +public class SmartBoolean { + private boolean value; + + public interface IListener { + 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; + } + +}