diff --git a/code/foundation/CMakeLists.txt b/code/foundation/CMakeLists.txt index e2d9077..023b4f2 100644 --- a/code/foundation/CMakeLists.txt +++ b/code/foundation/CMakeLists.txt @@ -20,6 +20,7 @@ add_library(eco2d-foundation STATIC src/models/prefabs/storage.c src/models/prefabs/furnace.c src/models/prefabs/blueprint.c + src/models/prefabs/splitter.c src/models/prefabs/craftbench.c src/pkt/packet.c diff --git a/code/foundation/src/gen/texgen_fallback.c b/code/foundation/src/gen/texgen_fallback.c index 6c5f7e4..39aa183 100644 --- a/code/foundation/src/gen/texgen_fallback.c +++ b/code/foundation/src/gen/texgen_fallback.c @@ -52,6 +52,7 @@ Texture2D texgen_build_sprite_fallback(asset_id id) { case ASSET_CHEST: return LoadTexEco("chest"); case ASSET_FURNACE: return LoadTexEco("furnace-export"); case ASSET_CRAFTBENCH: return LoadTexEco("craftbench"); + case ASSET_SPLITTER: return LoadTexEco("item_splitter"); default: break; } diff --git a/code/foundation/src/lists/assets_ids.lst b/code/foundation/src/lists/assets_ids.lst index bdde813..8672044 100644 --- a/code/foundation/src/lists/assets_ids.lst +++ b/code/foundation/src/lists/assets_ids.lst @@ -6,6 +6,7 @@ X(ASSET_PLAYER)\ X(ASSET_THING)\ X(ASSET_CHEST)\ + X(ASSET_SPLITTER)\ X(ASSET_FURNACE)\ X(ASSET_CRAFTBENCH)\ X(ASSET_BLUEPRINT_BEGIN)\ diff --git a/code/foundation/src/lists/assets_list.c b/code/foundation/src/lists/assets_list.c index ca5ff61..9b9243e 100644 --- a/code/foundation/src/lists/assets_list.c +++ b/code/foundation/src/lists/assets_list.c @@ -24,6 +24,7 @@ static asset assets[] = { ASSET_TEX(ASSET_PLANK), ASSET_TEX(ASSET_CHEST), ASSET_TEX(ASSET_FURNACE), + ASSET_TEX(ASSET_SPLITTER), ASSET_TEX(ASSET_CRAFTBENCH), ASSET_TEX(ASSET_BLUEPRINT), ASSET_TEX(ASSET_BLUEPRINT_DEMO_HOUSE), diff --git a/code/foundation/src/lists/entity_spawnlist.c b/code/foundation/src/lists/entity_spawnlist.c index 561aa15..bb7108c 100644 --- a/code/foundation/src/lists/entity_spawnlist.c +++ b/code/foundation/src/lists/entity_spawnlist.c @@ -3,6 +3,7 @@ #include "models/prefabs/furnace.h" #include "models/prefabs/blueprint.h" #include "models/prefabs/craftbench.h" +#include "models/prefabs/splitter.h" static struct { asset_id id; @@ -12,6 +13,7 @@ static struct { { .id = ASSET_CHEST, .proc = storage_spawn }, { .id = ASSET_FURNACE, .proc = furnace_spawn }, { .id = ASSET_CRAFTBENCH, .proc = craftbench_spawn }, + { .id = ASSET_SPLITTER, .proc = splitter_spawn }, { .id = ASSET_BLUEPRINT, .proc_udata = blueprint_spawn_udata }, }; diff --git a/code/foundation/src/lists/items_list.c b/code/foundation/src/lists/items_list.c index 968da21..96debe8 100644 --- a/code/foundation/src/lists/items_list.c +++ b/code/foundation/src/lists/items_list.c @@ -25,6 +25,7 @@ static item_desc items[] = { ITEM_ENT(ASSET_CHEST, 32, ASSET_CHEST), ITEM_ENT(ASSET_CRAFTBENCH, 32, ASSET_CRAFTBENCH), ITEM_ENT(ASSET_FURNACE, 32, ASSET_FURNACE), + ITEM_ENT(ASSET_SPLITTER, 32, ASSET_SPLITTER), ITEM_HOLD(ASSET_IRON_ORE, 64), ITEM_HOLD(ASSET_IRON_INGOT, 64), diff --git a/code/foundation/src/models/components.h b/code/foundation/src/models/components.h index 317ded5..17e5194 100644 --- a/code/foundation/src/models/components.h +++ b/code/foundation/src/models/components.h @@ -129,11 +129,27 @@ typedef struct { ecs_entity_t items[ITEMS_CONTAINER_SIZE]; } ItemContainer; +enum { + PRODUCER_PUSH_PRODUCT, + PRODUCER_PUSH_ANY, + PRODUCER_PUSH_NONE, +}; + +enum { + PRODUCER_CRAFT_WAITING, + PRODUCER_CRAFT_BUSY, + PRODUCER_CRAFT_ENQUEUED, + PRODUCER_CRAFT_AUTO, +}; + typedef struct { + asset_id target_item; asset_id processed_item; uint32_t processed_item_qty; float process_time; float energy_level; + uint8_t pending_task; + uint8_t push_filter; } Producer; typedef struct { diff --git a/code/foundation/src/models/crafting.c b/code/foundation/src/models/crafting.c index 1be7b8e..08b539b 100644 --- a/code/foundation/src/models/crafting.c +++ b/code/foundation/src/models/crafting.c @@ -51,7 +51,7 @@ bool craft_is_reagent_used_in_producer(asset_id reagent, asset_id producer) { return craft__find_num_recipes_by_reagent(producer, reagent) > 0; } -asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, uint32_t *quantity) { +asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id target, uint32_t *quantity) { ZPL_ASSERT_NOT_NULL(items); for (int i = 0; i < ITEMS_CONTAINER_SIZE; i++) { @@ -70,6 +70,12 @@ asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, uint32_t * continue; } + if (target != 0 && rec->product != target) { + // NOTE(zaklaus): we were asked to produce a specific product, + // however this recipe is not compatible, bail. + continue; + } + uint8_t skip_slot=0; // NOTE(zaklaus): analyse if all the reagents are present diff --git a/code/foundation/src/models/crafting.h b/code/foundation/src/models/crafting.h index bd21fd1..fa48675 100644 --- a/code/foundation/src/models/crafting.h +++ b/code/foundation/src/models/crafting.h @@ -7,7 +7,7 @@ // NOTE(zaklaus): resolves recipe dependencies and consumes reagents // to enqueue a production of a new item. // TODO(zaklaus): "items" is assumed to come from ItemContainer component. -asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, uint32_t *quantity); +asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id target, uint32_t *quantity); // NOTE(zaklaus): informs us on whether this product has any byproducts desired. asset_id craft_has_byproducts(asset_id product); diff --git a/code/foundation/src/models/prefabs/craftbench.c b/code/foundation/src/models/prefabs/craftbench.c index 2e6709e..af96173 100644 --- a/code/foundation/src/models/prefabs/craftbench.c +++ b/code/foundation/src/models/prefabs/craftbench.c @@ -14,6 +14,8 @@ uint64_t craftbench_spawn(void) { Producer *producer = ecs_get_mut(world_ecs(), e, Producer); *producer = (Producer){0}; producer->energy_level = 69.0f; + producer->pending_task = PRODUCER_CRAFT_WAITING; + producer->push_filter = PRODUCER_PUSH_NONE; ecs_set(world_ecs(), e, ItemRouter, {1}); return (uint64_t)e; diff --git a/code/foundation/src/models/prefabs/furnace.c b/code/foundation/src/models/prefabs/furnace.c index 7964812..4237600 100644 --- a/code/foundation/src/models/prefabs/furnace.c +++ b/code/foundation/src/models/prefabs/furnace.c @@ -14,6 +14,8 @@ uint64_t furnace_spawn(void) { Producer *producer = ecs_get_mut(world_ecs(), e, Producer); *producer = (Producer){0}; producer->energy_level = 69.0f; + producer->pending_task = PRODUCER_CRAFT_AUTO; + producer->push_filter = PRODUCER_PUSH_ANY; ecs_set(world_ecs(), e, ItemRouter, {1}); return (uint64_t)e; diff --git a/code/foundation/src/models/prefabs/splitter.c b/code/foundation/src/models/prefabs/splitter.c new file mode 100644 index 0000000..76ce690 --- /dev/null +++ b/code/foundation/src/models/prefabs/splitter.c @@ -0,0 +1,20 @@ +#include "splitter.h" +#include "models/device.h" +#include "world/world.h" + +#include "models/entity.h" +#include "models/components.h" + +uint64_t splitter_spawn(void) { + ecs_entity_t e = device_spawn(ASSET_SPLITTER); + + ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer); + *storage = (ItemContainer){0}; + + ecs_set(world_ecs(), e, ItemRouter, {1}); + return (uint64_t)e; +} + +void splitter_despawn(uint64_t ent_id) { + entity_despawn(ent_id); +} diff --git a/code/foundation/src/models/prefabs/splitter.h b/code/foundation/src/models/prefabs/splitter.h new file mode 100644 index 0000000..b25eea0 --- /dev/null +++ b/code/foundation/src/models/prefabs/splitter.h @@ -0,0 +1,7 @@ +#pragma once + +#include "platform/system.h" + +uint64_t splitter_spawn(void); +void splitter_despawn(uint64_t id); + diff --git a/code/foundation/src/systems/modules/system_logistics.c b/code/foundation/src/systems/modules/system_logistics.c index 068fac5..66152c7 100644 --- a/code/foundation/src/systems/modules/system_logistics.c +++ b/code/foundation/src/systems/modules/system_logistics.c @@ -65,6 +65,12 @@ void PushItemsOnNodes(ecs_iter_t *it) { // We need a way to refer to specific blocks in the world so we can do easy block ID checks // and re-build the cache when a change is detected. + Producer *producer = ecs_get_mut_if_ex(it->world, it->entities[i], Producer); + + if (producer) { + if (producer->push_filter == PRODUCER_PUSH_NONE) + continue; + } float push_dx[4], push_dy[4]; uint8_t nodes = CheckForNearbyBelts(&p[i], push_dx, push_dy); @@ -82,9 +88,19 @@ void PushItemsOnNodes(ecs_iter_t *it) { Item *item = item_get_data(item_slot_ent); if (!item) continue; - if (craft_is_reagent_used_in_producer(item->kind, d[i].asset)) { - // NOTE(zaklaus): this is an input reagent, keep it - continue; + if (producer) { + if (producer->push_filter == PRODUCER_PUSH_ANY) { + if (craft_is_reagent_used_in_producer(item->kind, d[i].asset)) { + // NOTE(zaklaus): this is an input reagent, keep it + continue; + } + } + else if (producer->push_filter == PRODUCER_PUSH_PRODUCT) { + if (producer->target_item != item->kind) { + // NOTE(zaklaus): this is not a producer's output, keep it + continue; + } + } } while (item->quantity > 0 && num_nodes > 0) { diff --git a/code/foundation/src/systems/modules/system_producer.c b/code/foundation/src/systems/modules/system_producer.c index 414f0d6..5bc7d3d 100644 --- a/code/foundation/src/systems/modules/system_producer.c +++ b/code/foundation/src/systems/modules/system_producer.c @@ -31,9 +31,21 @@ void ProduceItems(ecs_iter_t *it) { uint64_t e = item_spawn(producer[i].processed_item, producer[i].processed_item_qty); entity_set_position(e, p[i].x, p[i].y); producer[i].processed_item = 0; + + if (producer[i].pending_task == PRODUCER_CRAFT_BUSY) + producer[i].pending_task = PRODUCER_CRAFT_WAITING; } else { - producer[i].processed_item = craft_perform_recipe(storage[i].items, d[i].asset, &producer[i].processed_item_qty); - producer[i].process_time = game_time() + game_rules.furnace_cook_time; + if (producer[i].pending_task != PRODUCER_CRAFT_WAITING) { + producer[i].processed_item = craft_perform_recipe(storage[i].items, d[i].asset, producer[i].target_item, &producer[i].processed_item_qty); + producer[i].process_time = game_time() + game_rules.furnace_cook_time; + + if (producer[i].pending_task == PRODUCER_CRAFT_ENQUEUED) { + if (producer[i].processed_item > 0) + producer[i].pending_task = PRODUCER_CRAFT_BUSY; + else + producer[i].pending_task = PRODUCER_CRAFT_WAITING; + } + } } } }