diff --git a/src/main/java/xyz/valnet/engine/math/Box.java b/src/main/java/xyz/valnet/engine/math/Box.java index dbc8eb1..3dca1cb 100644 --- a/src/main/java/xyz/valnet/engine/math/Box.java +++ b/src/main/java/xyz/valnet/engine/math/Box.java @@ -152,4 +152,8 @@ public class Box implements Serializable { (float) Math.ceil(y2) ); } + + public TileBox asTileBox() { + return new TileBox(pos.asInt(), dim.asInt()); + } } diff --git a/src/main/java/xyz/valnet/engine/math/TileBox.java b/src/main/java/xyz/valnet/engine/math/TileBox.java index 1d3f8aa..0e4af53 100644 --- a/src/main/java/xyz/valnet/engine/math/TileBox.java +++ b/src/main/java/xyz/valnet/engine/math/TileBox.java @@ -1,6 +1,10 @@ package xyz.valnet.engine.math; import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class TileBox implements Serializable { public final int x, y; @@ -49,6 +53,16 @@ public class TileBox implements Serializable { } } + public List getTiles() { + List tiles = new ArrayList<>(); + for(int i = 0; i < w; i ++) { + for(int j = 0; j < h; j ++) { + tiles.add(new Vector2i(x + i, y + j)); + } + } + return tiles; + } + public static TileBox fromPoints(int x, int y, int x2, int y2) { return new TileBox( x <= x2 ? x : x2, diff --git a/src/main/java/xyz/valnet/hadean/designation/CutTreesDesignation.java b/src/main/java/xyz/valnet/hadean/designation/CutTreesDesignation.java index 2f91b49..bae82ec 100644 --- a/src/main/java/xyz/valnet/hadean/designation/CutTreesDesignation.java +++ b/src/main/java/xyz/valnet/hadean/designation/CutTreesDesignation.java @@ -16,6 +16,6 @@ public class CutTreesDesignation extends Designation { @Override public String getBuildTabName() { - return "ChopTrees"; + return "Chop Trees"; } } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/jobs/Job.java b/src/main/java/xyz/valnet/hadean/gameobjects/jobs/Job.java index d0e531d..8a162a2 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/jobs/Job.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/jobs/Job.java @@ -18,6 +18,7 @@ public class Job extends GameObject { private Job that = this; private List closedListeners = new ArrayList(); + private List completedListeners = new ArrayList(); public abstract class JobStep implements Serializable { public abstract Vector2i[] getLocations(); @@ -27,6 +28,10 @@ public class Job extends GameObject { public abstract boolean isValid(); } + // pickup and dropoff should be all in one step, as each step should + // only need state tracked for the job, not the worker. + // workers can change between steps. + @Deprecated public class PickupItem extends JobStep { public Item item; @@ -66,6 +71,10 @@ public class Job extends GameObject { } } + // pickup and dropoff should be all in one step, as each step should + // only need state tracked for the job, not the worker. + // workers can change between steps. + @Deprecated public class PickupItemByPredicate extends JobStep { public IItemPredicate predicate; @@ -156,6 +165,7 @@ public class Job extends GameObject { private String name; private int step; private boolean hasClosed = false; + private boolean hasCompleted = false; public void reset() { step = 0; @@ -179,7 +189,7 @@ public class Job extends GameObject { public void nextStep() { step ++; if(isCompleted()) { - close(); + completed(); remove(this); } } @@ -202,6 +212,15 @@ public class Job extends GameObject { public void apply(); } + private final void completed() { + if(hasCompleted) return; + hasCompleted = true; + for(Callback callback : completedListeners) { + callback.apply(); + } + close(); + } + public void close() { if(hasClosed) return; hasClosed = true; @@ -218,6 +237,14 @@ public class Job extends GameObject { closedListeners.remove(callback); } + public void registerCompletedListener(Callback callback) { + completedListeners.add(callback); + } + + public void unregisterCompletedListener(Callback callback) { + completedListeners.remove(callback); + } + public boolean isValid() { for(JobStep step : steps) { if(!step.isValid()) return false; diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/jobs/JobBoard.java b/src/main/java/xyz/valnet/hadean/gameobjects/jobs/JobBoard.java index a8e9485..1b3d9c6 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/jobs/JobBoard.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/jobs/JobBoard.java @@ -77,6 +77,7 @@ public class JobBoard extends GameObject { } public void postJob(Job job) { + if(!job.inScene()) add(job); job.registerClosedListener(() -> { if(allocations.values().contains(job)) { List toFire = new ArrayList(); diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/jobs/WorkOrder.java b/src/main/java/xyz/valnet/hadean/gameobjects/jobs/WorkOrder.java index 38a8d1d..b06b31e 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/jobs/WorkOrder.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/jobs/WorkOrder.java @@ -1,6 +1,13 @@ package xyz.valnet.hadean.gameobjects.jobs; +import java.util.HashSet; +import java.util.Set; + +import xyz.valnet.engine.math.Vector2i; import xyz.valnet.engine.scenegraph.GameObject; +import xyz.valnet.hadean.gameobjects.worldobjects.items.Boulder; +import xyz.valnet.hadean.gameobjects.worldobjects.items.Item; +import xyz.valnet.hadean.interfaces.IItemReceiver; import xyz.valnet.hadean.interfaces.IWorkshop; public class WorkOrder extends GameObject { @@ -9,6 +16,9 @@ public class WorkOrder extends GameObject { private int count = 10; private String name = "Cut Stone Blocks"; private IWorkshop shop = null; + private float maxWork = 1000; + + private Set relatedJobs; public boolean getRecurring() { return recurring; @@ -22,6 +32,10 @@ public class WorkOrder extends GameObject { return name; } + public float getMaxWork() { + return maxWork; + } + public void increaseCount() { count ++; } @@ -40,6 +54,47 @@ public class WorkOrder extends GameObject { } public boolean isSpecificToShop(IWorkshop shop) { - return this.shop != null && shop == this.shop; + return this.shop != null && this.shop == shop; + } + + @Override + protected void create() { + super.create(); + relatedJobs = new HashSet<>(); + } + + public boolean isBeingWorkedOn() { + return relatedJobs.size() > 0; + } + + public boolean canCreateJob() { + return count > relatedJobs.size(); + } + + public Job createNextJob(IWorkshop shop) { + Job job = new Job("Cut brickies"); + job.addStep(job.new PickupItemByPredicate(Boulder.BOULDER_PREDICATE)); + job.addStep(job.new DropoffPredicateAtItemReceiver(new IItemReceiver() { + @Override + public boolean receive(Item item) { + + return false; + } + + @Override + public Vector2i[] getItemDropoffLocations() { + return shop.getWorkablePositions(); + } + }, Boulder.BOULDER_PREDICATE)); + job.addStep(job.new Work(shop)); + job.registerCompletedListener(() -> { + decreaseCount(); + + }); + job.registerClosedListener(() -> { + relatedJobs.remove(job); + }); + get(JobBoard.class).postJob(job); + return job; } } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/WorldObject.java b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/WorldObject.java index 32d2ef8..e6c18a1 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/WorldObject.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/WorldObject.java @@ -11,8 +11,9 @@ import xyz.valnet.hadean.gameobjects.Camera; import xyz.valnet.hadean.gameobjects.terrain.Terrain; import xyz.valnet.hadean.gameobjects.terrain.Tile; import xyz.valnet.hadean.interfaces.ITileThing; +import xyz.valnet.hadean.interfaces.IWorldObject; -public abstract class WorldObject extends GameObject { +public abstract class WorldObject extends GameObject implements IWorldObject { // TODO make it just a box lawl private int x; @@ -119,6 +120,10 @@ public abstract class WorldObject extends GameObject { return terrain.getTile(x, y); } + public Tile getTile(int x, int y) { + return terrain.getTile(x, y); + } + public Set getTiles() { return linkedTiles; } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/agents/pawn/Pawn.java b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/agents/pawn/Pawn.java index 086e94c..c740bed 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/agents/pawn/Pawn.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/agents/pawn/Pawn.java @@ -14,6 +14,7 @@ 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.ui.tabs.DebugTab; import xyz.valnet.hadean.gameobjects.worldobjects.agents.Agent; import xyz.valnet.hadean.gameobjects.worldobjects.items.Item; import xyz.valnet.hadean.interfaces.IItemPredicate; @@ -42,6 +43,9 @@ public class Pawn extends Agent { public void pickupItemByPredicate(IItemPredicate itemPredicate) { Item item = getTile().pickupByItemPredicate(itemPredicate); + if(item == null) { + DebugTab.log("This is an issue"); + } inventory.add(item); } @@ -66,7 +70,8 @@ public class Pawn extends Agent { return; } inventory.remove(item); - add(item); + // TODO this might need to exist at some point + // add(item); receiver.receive(item); } diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/Construction.java b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/Construction.java index 4a387d6..207ab5e 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/Construction.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/Construction.java @@ -18,7 +18,7 @@ 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 { +public abstract class Construction extends Buildable { private float work = 0; @@ -36,7 +36,23 @@ public abstract class Construction extends Buildable implements IItemReceiver { Job job = get(JobBoard.class).postSimpleItemRequirementJob( "Haul items to building", getBuildingMaterial(), - this + new IItemReceiver() { + + @Override + public final boolean receive(Item item) { + if(item == null) return false; + if(!item.matches(getBuildingMaterial())) return false; + remove(item); + containedItems.add(item); + return true; + } + + @Override + public Vector2i[] getItemDropoffLocations() { + return getWorldBox().getBorders(); + } + + } ); job.registerClosedListener(() -> { postNextJob(); @@ -108,20 +124,6 @@ public abstract class Construction extends Buildable implements IItemReceiver { return work / getMaxWork(); } - @Override - public final boolean receive(Item item) { - if(item == null) return false; - if(!item.matches(getBuildingMaterial())) return false; - remove(item); - containedItems.add(item); - return true; - } - - @Override - public Vector2i[] getItemDropoffLocations() { - return getWorldBox().getBorders(); - } - @Override public void render() { Sprite sprite = getDefaultSprite(); diff --git a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/MasonWorkshop.java b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/MasonWorkshop.java index f92a3e6..c1737b0 100644 --- a/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/MasonWorkshop.java +++ b/src/main/java/xyz/valnet/hadean/gameobjects/worldobjects/constructions/MasonWorkshop.java @@ -1,8 +1,13 @@ package xyz.valnet.hadean.gameobjects.worldobjects.constructions; import xyz.valnet.engine.graphics.Sprite; +import xyz.valnet.engine.math.TileBox; import xyz.valnet.engine.math.Vector2i; +import xyz.valnet.hadean.gameobjects.jobs.Job; +import xyz.valnet.hadean.gameobjects.jobs.WorkOrder; +import xyz.valnet.hadean.gameobjects.jobs.WorkOrderManager; import xyz.valnet.hadean.gameobjects.ui.WorkshopOrdersUI; +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.IWorkshop; @@ -13,6 +18,10 @@ public class MasonWorkshop extends Construction implements IWorkshop { private static Action OPEN_ORDERS = new Action("Orders"); private transient WorkshopOrdersUI ordersWindow; + private WorkOrderManager manager; + + // TODO the job itself should have the work amount... + private float workDone = 0; @Override protected IItemPredicate getBuildingMaterial() { @@ -62,6 +71,7 @@ public class MasonWorkshop extends Construction implements IWorkshop { protected void connect() { super.connect(); ordersWindow = get(WorkshopOrdersUI.class); + manager = get(WorkOrderManager.class); } @Override @@ -73,5 +83,52 @@ public class MasonWorkshop extends Construction implements IWorkshop { public String getBuildTabCategory() { return "Workshops"; } + + @Override + public boolean doWork(float dTime) { + workDone += dTime; + return workDone > order.getMaxWork(); + } + + @Override + public Vector2i[] getWorkablePositions() { + return getWorldBox().getBorders(); + } + + @Override + public String getJobName() { + return "Do Work as Workshop"; + } + + @Override + public TileBox getSpawnableArea() { + return getWorldBox().asTileBox(); + } + + private Job job = null; + private WorkOrder order = null; + + @Override + public void update(float dTime) { + super.update(dTime); + if(job == null) { + tryGetJob(); + } + } + + private final void tryGetJob() { + for(WorkOrder order : manager.getOrders(this)) { + if(order.canCreateJob()) { + this.order = order; + job = order.createNextJob(this); + job.registerClosedListener(() -> { + workDone = 0; + job = null; + this.order = null; + }); + return; + } + } + } } diff --git a/src/main/java/xyz/valnet/hadean/interfaces/IItemSpawner.java b/src/main/java/xyz/valnet/hadean/interfaces/IItemSpawner.java new file mode 100644 index 0000000..9a82915 --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/interfaces/IItemSpawner.java @@ -0,0 +1,17 @@ +package xyz.valnet.hadean.interfaces; + +import xyz.valnet.engine.math.TileBox; +import xyz.valnet.hadean.gameobjects.worldobjects.items.Item; + +public interface IItemSpawner extends IWorldObject { + public abstract TileBox getSpawnableArea(); + + public default void spawn(Item item) { + var tiles = getSpawnableArea().getTiles(); + while(tiles.size() > 0) { + int idx = (int) Math.floor(Math.random() * tiles.size()); + var pos = tiles.get(idx); + getTile(pos.x, pos.y); + } + } +} diff --git a/src/main/java/xyz/valnet/hadean/interfaces/IWorkable.java b/src/main/java/xyz/valnet/hadean/interfaces/IWorkable.java index ae59cf4..0df9104 100644 --- a/src/main/java/xyz/valnet/hadean/interfaces/IWorkable.java +++ b/src/main/java/xyz/valnet/hadean/interfaces/IWorkable.java @@ -7,5 +7,7 @@ import xyz.valnet.engine.math.Vector2i; public interface IWorkable extends Serializable { public boolean doWork(float dTime); public Vector2i[] getWorkablePositions(); + // we should honestly switch to only have names of jobs not steps... + @Deprecated public String getJobName(); } diff --git a/src/main/java/xyz/valnet/hadean/interfaces/IWorkshop.java b/src/main/java/xyz/valnet/hadean/interfaces/IWorkshop.java index 3c3388a..e3f219c 100644 --- a/src/main/java/xyz/valnet/hadean/interfaces/IWorkshop.java +++ b/src/main/java/xyz/valnet/hadean/interfaces/IWorkshop.java @@ -1,5 +1,6 @@ package xyz.valnet.hadean.interfaces; -public interface IWorkshop extends ISelectable { - +public interface IWorkshop extends ISelectable, + IWorkable, + IItemSpawner { } diff --git a/src/main/java/xyz/valnet/hadean/interfaces/IWorldObject.java b/src/main/java/xyz/valnet/hadean/interfaces/IWorldObject.java new file mode 100644 index 0000000..8c24db1 --- /dev/null +++ b/src/main/java/xyz/valnet/hadean/interfaces/IWorldObject.java @@ -0,0 +1,7 @@ +package xyz.valnet.hadean.interfaces; + +import xyz.valnet.hadean.gameobjects.terrain.Tile; + +public interface IWorldObject { + public Tile getTile(int x, int y); +}