code: storage system and mouse picking

isolation_bkp/dynres
Dominik Madarász 2022-08-09 16:46:23 +02:00
parent 4164e62a7b
commit d0d69e7039
34 changed files with 693 additions and 192 deletions

View File

@ -18,6 +18,7 @@ add_executable(eco2d
src/packet.c src/packet.c
src/player.c src/player.c
src/vehicle.c src/vehicle.c
src/storage.c
src/signal_handling.c src/signal_handling.c
src/profiler.c src/profiler.c
src/debug_ui.c src/debug_ui.c

View File

@ -6,11 +6,13 @@
typedef enum { typedef enum {
// NOTE(zaklaus): Debug // NOTE(zaklaus): Debug
ASSET_EMPTY, ASSET_EMPTY,
ASSET_BLANK,
ASSET_BUILDMODE_HIGHLIGHT, ASSET_BUILDMODE_HIGHLIGHT,
// NOTE(zaklaus): entities // NOTE(zaklaus): entities
ASSET_PLAYER, ASSET_PLAYER,
ASSET_THING, ASSET_THING,
ASSET_CHEST,
// NOTE(zaklaus): items // NOTE(zaklaus): items
ASSET_DEMO_ICEMAKER, ASSET_DEMO_ICEMAKER,

View File

@ -12,8 +12,10 @@
static asset assets[] = { static asset assets[] = {
ASSET_TEX(ASSET_EMPTY), ASSET_TEX(ASSET_EMPTY),
ASSET_TEX(ASSET_BLANK),
ASSET_TEX(ASSET_BUILDMODE_HIGHLIGHT), ASSET_TEX(ASSET_BUILDMODE_HIGHLIGHT),
ASSET_TEX(ASSET_DEMO_ICEMAKER), ASSET_TEX(ASSET_DEMO_ICEMAKER),
ASSET_TEX(ASSET_CHEST),
// NOTE(zaklaus): blocks // NOTE(zaklaus): blocks
ASSET_TEX(ASSET_FENCE), ASSET_TEX(ASSET_FENCE),

View File

@ -13,6 +13,8 @@ typedef enum {
RPKIND_PLACE_ERASE_CHANGES, RPKIND_PLACE_ERASE_CHANGES,
RPKIND_SPAWN_CIRCLING_DRIVER, RPKIND_SPAWN_CIRCLING_DRIVER,
RPKIND_SPAWN_ICEMAKER_ITEM, RPKIND_SPAWN_ICEMAKER_ITEM,
RPKIND_SPAWN_CHEST,
RPKIND_SPAWN_BELT,
} replay_kind; } replay_kind;
typedef struct { typedef struct {
@ -174,6 +176,8 @@ void ActPlaceIceRink(void);
void ActSpawnCirclingDriver(void); void ActSpawnCirclingDriver(void);
void ActEraseWorldChanges(void); void ActEraseWorldChanges(void);
void ActSpawnIcemaker(void); void ActSpawnIcemaker(void);
void ActSpawnChest(void);
void ActSpawnBelt(void);
void debug_replay_update(void) { void debug_replay_update(void) {
if (!is_playing) return; if (!is_playing) return;
@ -224,6 +228,12 @@ void debug_replay_update(void) {
case RPKIND_SPAWN_ICEMAKER_ITEM:{ case RPKIND_SPAWN_ICEMAKER_ITEM:{
ActSpawnIcemaker(); ActSpawnIcemaker();
}break; }break;
case RPKIND_SPAWN_CHEST:{
ActSpawnChest();
}break;
case RPKIND_SPAWN_BELT:{
ActSpawnBelt();
}break;
default: { default: {
ZPL_PANIC("unreachable"); ZPL_PANIC("unreachable");
}break; }break;

View File

@ -133,6 +133,8 @@ static debug_item items[] = {
{ .kind = DITEM_BUTTON, .name = "erase world changes", .on_click = ActEraseWorldChanges }, { .kind = DITEM_BUTTON, .name = "erase world changes", .on_click = ActEraseWorldChanges },
{ .kind = DITEM_BUTTON, .name = "spawn circling driver", .on_click = ActSpawnCirclingDriver }, { .kind = DITEM_BUTTON, .name = "spawn circling driver", .on_click = ActSpawnCirclingDriver },
{ .kind = DITEM_BUTTON, .name = "spawn icemaker item", .on_click = ActSpawnIcemaker }, { .kind = DITEM_BUTTON, .name = "spawn icemaker item", .on_click = ActSpawnIcemaker },
{ .kind = DITEM_BUTTON, .name = "spawn chest", .on_click = ActSpawnChest },
{ .kind = DITEM_BUTTON, .name = "spawn belt", .on_click = ActSpawnBelt },
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "demo npcs", .name = "demo npcs",

View File

@ -32,6 +32,30 @@ ActSpawnIcemaker(void) {
debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM); debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM);
} }
void
ActSpawnChest(void) {
ecs_entity_t e = item_spawn(ASSET_CHEST, 32);
ecs_entity_t plr = camera_get().ent_id;
Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position);
*dest = *origin;
debug_replay_special_action(RPKIND_SPAWN_CHEST);
}
void
ActSpawnBelt(void) {
ecs_entity_t e = item_spawn(ASSET_BELT, 999);
ecs_entity_t plr = camera_get().ent_id;
Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position);
*dest = *origin;
debug_replay_special_action(RPKIND_SPAWN_BELT);
}
void void
ActSpawnCirclingDriver(void) { ActSpawnCirclingDriver(void) {
ecs_entity_t plr = camera_get().ent_id; ecs_entity_t plr = camera_get().ent_id;

View File

@ -12,3 +12,4 @@ void entity_set_position(uint64_t ent_id, float x, float y);
void entity_wake(uint64_t ent_id); void entity_wake(uint64_t ent_id);
void entity_update_action_timers(); void entity_update_action_timers();
bool entity_can_stream(uint64_t ent_id); bool entity_can_stream(uint64_t ent_id);

View File

@ -36,6 +36,14 @@ pkt_desc pkt_entity_view_desc[] = {
{ PKT_UINT(entity_view, selected_item) }, { PKT_UINT(entity_view, selected_item) },
{ PKT_ARRAY(entity_view, items) }, { PKT_ARRAY(entity_view, items) },
{ PKT_UINT(entity_view, pick_ent) },
{ PKT_UINT(entity_view, sel_ent) },
{ PKT_KEEP_IF(entity_view, has_storage_items, true, 3) },
{ PKT_UINT(entity_view, has_storage_items) },
{ PKT_UINT(entity_view, storage_selected_item) },
{ PKT_ARRAY(entity_view, storage_items) },
{ PKT_END }, { PKT_END },
}; };

View File

@ -10,6 +10,7 @@ typedef enum {
EKIND_SERVER = 0, EKIND_SERVER = 0,
EKIND_PLAYER, EKIND_PLAYER,
EKIND_ITEM, EKIND_ITEM,
EKIND_DEVICE,
EKIND_VEHICLE, EKIND_VEHICLE,
EKIND_DEMO_NPC, EKIND_DEMO_NPC,
EKIND_MONSTER, EKIND_MONSTER,
@ -66,6 +67,15 @@ typedef struct entity_view {
ItemDrop items[ITEMS_INVENTORY_SIZE]; ItemDrop items[ITEMS_INVENTORY_SIZE];
uint8_t selected_item; uint8_t selected_item;
// NOTE(zaklaus): storage interface
uint8_t has_storage_items;
ItemDrop storage_items[ITEMS_CONTAINER_SIZE];
uint8_t storage_selected_item;
// NOTE(zaklaus): entity picking
uint64_t pick_ent;
uint64_t sel_ent;
// NOTE(zaklaus): internals // NOTE(zaklaus): internals
uint8_t layer_id; uint8_t layer_id;
uint64_t last_update; uint64_t last_update;

View File

@ -250,6 +250,14 @@ void game_action_send_keystate(game_keystate_data *data) {
pkt_send_keystate_send(active_viewer->view_id, data); pkt_send_keystate_send(active_viewer->view_id, data);
} }
void game_action_send_blockpos(float mx, float my) {
pkt_send_blockpos data = {
.mx = mx,
.my = my
};
pkt_send_blockpos_send(active_viewer->view_id, &data);
}
void game_request_close() { void game_request_close() {
game_should_close = true; game_should_close = true;
if (game_mode != GAMEKIND_HEADLESS) { if (game_mode != GAMEKIND_HEADLESS) {

View File

@ -35,3 +35,4 @@ entity_view *game_world_view_active_get_entity(uint64_t ent_id);
//~ NOTE(zaklaus): viewer -> host actions //~ NOTE(zaklaus): viewer -> host actions
void game_action_send_keystate(game_keystate_data *data); void game_action_send_keystate(game_keystate_data *data);
void game_action_send_blockpos(float mx, float my);

View File

@ -45,6 +45,7 @@ Texture2D texgen_build_anim(asset_id id, int64_t counter) {
Texture2D texgen_build_sprite(asset_id id) { Texture2D texgen_build_sprite(asset_id id) {
switch (id) { switch (id) {
case ASSET_BLANK: return GenColorEco(WHITE); break;
case ASSET_BUILDMODE_HIGHLIGHT: return GenColorEco(WHITE); break; case ASSET_BUILDMODE_HIGHLIGHT: return GenColorEco(WHITE); break;
// NOTE(zaklaus): items // NOTE(zaklaus): items

View File

@ -19,18 +19,13 @@ void buildmode_draw(void) {
if (inv_is_inside) return; if (inv_is_inside) return;
camera cam = camera_get(); camera cam = camera_get();
camera old_cam = cam; camera old_cam = cam;
Vector2 mpos = GetMousePosition();
entity_view *e = game_world_view_active_get_entity(cam.ent_id); entity_view *e = game_world_view_active_get_entity(cam.ent_id);
if (!e) return; if (!e) return;
float zoom = renderer_zoom_get(); float zoom = renderer_zoom_get();
mpos.x -= screenWidth/2.0f; float mx = 0, my = 0;
mpos.y -= screenHeight/2.0f; platform_get_block_realpos(&mx, &my);
cam.x += mpos.x*(1.0f/zoom); cam.x = (double)mx;
cam.y += mpos.y*(1.0f/zoom); cam.y = (double)my;
cam.x = ((int32_t)cam.x / (int32_t)(WORLD_BLOCK_SIZE)) * WORLD_BLOCK_SIZE;
cam.y = ((int32_t)cam.y / (int32_t)(WORLD_BLOCK_SIZE)) * WORLD_BLOCK_SIZE;
cam.x += WORLD_BLOCK_SIZE/2.0f;
cam.y += WORLD_BLOCK_SIZE/2.0f;
// NOTE(zaklaus): Check distance // NOTE(zaklaus): Check distance
double dx = old_cam.x - cam.x; double dx = old_cam.x - cam.x;

View File

@ -1,19 +1,130 @@
static uint8_t inv_selected_item = 0; typedef struct {
static bool inv_drop_item = false; uint8_t selected_item;
bool drop_item;
bool item_is_held;
uint8_t held_item_idx;
ItemDrop held_item;
bool is_inside;
bool storage_action;
bool swap;
uint8_t swap_from;
uint8_t swap_to;
} inv_keystate;
static inv_keystate player_inv = {0};
static inv_keystate storage_inv = {0};
bool inv_is_open = false; bool inv_is_open = false;
static bool inv_item_is_held = false;
static uint8_t inv_held_item_idx = 0;
static ItemDrop inv_held_item = {0};
static bool inv_swap = false;
static uint8_t inv_swap_from = 0;
static uint8_t inv_swap_to = 0;
bool inv_is_inside = false; bool inv_is_inside = false;
bool inv_is_storage_action = false;
bool inv_swap_storage = false;
void inventory_draw_panel(entity_view *e, bool is_player, float sx, float sy){
if (!e->has_items && is_player)
return;
if (!e->has_storage_items && !is_player)
return;
float x = sx;
float y = sy;
const int32_t grid_size = (is_player) ? (64*3) : (64*4);
const int32_t inv_size = (is_player) ? ITEMS_INVENTORY_SIZE : ITEMS_CONTAINER_SIZE;
const int32_t inv_cols = (is_player) ? 3 : 4;
inv_keystate *inv = (!is_player) ? &storage_inv : &player_inv;
inv_keystate *inv2 = (is_player) ? &storage_inv : &player_inv;
inv->is_inside = check_mouse_area(sx, sy, (float)grid_size, (float)grid_size) != DAREA_OUTSIDE;
inv_is_inside |= inv->is_inside;
for (int32_t i = 0; i < inv_size; i += 1) {
{
debug_area_status area = check_mouse_area(x, y, 64, 64);
Color color = RAYWHITE;
ItemDrop *item = (is_player) ? &e->items[i] : &e->storage_items[i];
if (area == DAREA_HOVER) {
color = YELLOW;
} else if (area == DAREA_PRESS && inv2->item_is_held){
color = VIOLET;
inv_swap_storage = true;
inv_is_storage_action = true;
inv->item_is_held = false;
inv2->item_is_held = false;
inv->selected_item = i;
inv->swap = true;
inv->swap_from = inv2->held_item_idx;
inv->swap_to = i;
} else if (area == DAREA_PRESS && !inv->item_is_held) {
color = VIOLET;
inv->selected_item = i;
inv_is_storage_action = true;
} else if (area == DAREA_PRESS && inv->item_is_held) {
color = VIOLET;
inv->selected_item = i;
inv->item_is_held = false;
inv->swap = true;
inv->swap_from = inv->held_item_idx;
inv->swap_to = i;
inv_is_storage_action = true;
} else if (area == DAREA_HELD && item->quantity > 0 && !inv->item_is_held) {
inv->selected_item = i;
inv->item_is_held = true;
inv->held_item = *item;
inv->held_item_idx = i;
inv_is_storage_action = true;
} else if (i == inv->selected_item) {
color = RED;
}
DrawRectangleLinesEco(x, y, 64, 64, color);
if (item->quantity > 0) {
DrawTexturePro(GetSpriteTexture2D(assets_find(item->kind)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, WHITE);
DrawTextEco(zpl_bprintf("%d", item->quantity), x+5, y+5, 16, RAYWHITE, 0.0f);
}
}
x += 64;
if ((i+1) % inv_cols == 0) {
x = sx;
y += 64;
}
}
if (inv->item_is_held) {
Vector2 mpos = GetMousePosition();
mpos.x -= 32;
mpos.y -= 32;
DrawTexturePro(GetSpriteTexture2D(assets_find(inv->held_item.kind)), ASSET_SRC_RECT(), ASSET_DST_RECT(mpos.x, mpos.y), (Vector2){0.5f,0.5f}, 0.0f, ColorAlpha(WHITE, 0.8f));
DrawTextEco(zpl_bprintf("%d", inv->held_item.quantity), mpos.x, mpos.y, 16, RAYWHITE, 0.0f);
if (!inv->is_inside && IsMouseButtonReleased(MOUSE_LEFT_BUTTON) && !inv2->is_inside) {
inv->drop_item = true;
inv->item_is_held = false;
inv_is_storage_action = true;
}
}
// NOTE(zaklaus): switch it off if is_player
if (is_player)
inv_is_storage_action = false;
}
void inventory_reset_states(inv_keystate *ik) {
ik->drop_item = false;
ik->swap = false;
}
void inventory_draw() { void inventory_draw() {
inv_drop_item = false; inv_is_storage_action = false;
inv_swap = false; inv_is_inside = false;
inv_swap_storage = false;
inventory_reset_states(&player_inv);
inventory_reset_states(&storage_inv);
camera cam = camera_get(); camera cam = camera_get();
entity_view *e = game_world_view_active_get_entity(cam.ent_id); entity_view *e = game_world_view_active_get_entity(cam.ent_id);
@ -27,67 +138,6 @@ void inventory_draw() {
return; return;
} }
float sx = screenWidth/2.0f + 128; inventory_draw_panel(e, true, screenWidth/2.0f + 128, screenHeight/2.0f - 96);
float sy = screenHeight/2.0f - 96; inventory_draw_panel(e, false, screenWidth/2.0f - 384, screenHeight/2.0f - 128);
float x = sx;
float y = sy;
inv_is_inside = check_mouse_area(sx, sy, 64*3, 64*3) != DAREA_OUTSIDE;
for (int32_t i = 0; i < ITEMS_INVENTORY_SIZE; i += 1) {
{
debug_area_status area = check_mouse_area(x, y, 64, 64);
Color color = RAYWHITE;
ItemDrop *item = &e->items[i];
if (area == DAREA_HOVER) {
color = YELLOW;
} else if (area == DAREA_PRESS && !inv_item_is_held) {
color = VIOLET;
inv_selected_item = i;
} else if (area == DAREA_PRESS && inv_item_is_held) {
color = VIOLET;
inv_selected_item = i;
inv_item_is_held = false;
inv_swap = true;
inv_swap_from = inv_held_item_idx;
inv_swap_to = i;
} else if (area == DAREA_HELD && item->quantity > 0 && !inv_item_is_held) {
inv_selected_item = i;
inv_held_item = *item;
inv_item_is_held = true;
inv_held_item_idx = i;
} else if (i == inv_selected_item) {
color = RED;
}
DrawRectangleLinesEco(x, y, 64, 64, color);
if (item->quantity > 0) {
DrawTexturePro(GetSpriteTexture2D(assets_find(item->kind)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, WHITE);
DrawTextEco(zpl_bprintf("%d", item->quantity), x+5, y+5, 16, RAYWHITE, 0.0f);
}
}
x += 64;
if ((i+1) % 3 == 0) {
x = sx;
y += 64;
}
}
if (inv_item_is_held) {
Vector2 mpos = GetMousePosition();
mpos.x -= 32;
mpos.y -= 32;
DrawTexturePro(GetSpriteTexture2D(assets_find(inv_held_item.kind)), ASSET_SRC_RECT(), ASSET_DST_RECT(mpos.x, mpos.y), (Vector2){0.5f,0.5f}, 0.0f, ColorAlpha(WHITE, 0.8f));
DrawTextEco(zpl_bprintf("%d", inv_held_item.quantity), mpos.x, mpos.y, 16, RAYWHITE, 0.0f);
debug_area_status area = check_mouse_area(sx, sy, 64*3, 64*3);
if (area == DAREA_OUTSIDE && IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
inv_drop_item = true;
inv_item_is_held = false;
}
}
} }

View File

@ -73,6 +73,25 @@ void item_use(ecs_world_t *ecs, ItemDrop *it, Position p, uint64_t udata) {
world_chunk_replace_block(l.chunk_id, l.id, blocks_find(desc->place.kind + (asset_id)udata)); world_chunk_replace_block(l.chunk_id, l.id, blocks_find(desc->place.kind + (asset_id)udata));
it->quantity--; it->quantity--;
}break; }break;
case UKIND_PLACE_ITEM:{
world_block_lookup l = world_block_from_realpos(p.x, p.y);
if (l.is_outer && l.bid > 0) {
return;
}
// NOTE(zaklaus): This is an inner layer block, we can't build over it if it has a collision!
else if (l.bid > 0 && blocks_get_flags(l.bid) & (BLOCK_FLAG_COLLISION|BLOCK_FLAG_ESSENTIAL)) {
return;
}
ecs_entity_t e = desc->place_item.spawn_proc();
ZPL_ASSERT(world_entity_valid(e));
Position *pos = ecs_get_mut(ecs, e, Position);
pos->x = p.x;
pos->y = p.y;
it->quantity--;
}break;
} }
} }

View File

@ -31,6 +31,10 @@ typedef struct {
struct { struct {
asset_id id; asset_id id;
} proxy; } proxy;
struct {
uint64_t (*spawn_proc)();
} place_item;
}; };
} item_desc; } item_desc;

View File

@ -1,4 +1,5 @@
#include "items.h" #include "items.h"
#include "entity_view.h"
#define ITEM_HOLD(asset, qty)\ #define ITEM_HOLD(asset, qty)\
{\ {\
@ -37,9 +38,22 @@
}\ }\
} }
#define ITEM_ENT(asset, qty, proc)\
{\
.kind = asset,\
.usage = UKIND_PLACE_ITEM,\
.max_quantity = qty,\
.place_item = {\
.spawn_proc = proc\
}\
}
#define ITEM_SELF(asset, qty) ITEM_BLOCK(asset, qty, asset) #define ITEM_SELF(asset, qty) ITEM_BLOCK(asset, qty, asset)
#define ITEM_SELF_DIR(asset, qty) ITEM_BLOCK_DIR(asset, qty, asset) #define ITEM_SELF_DIR(asset, qty) ITEM_BLOCK_DIR(asset, qty, asset)
// NOTE(zaklaus): access to spawners
#include "storage.h"
static item_desc items[] = { static item_desc items[] = {
{ {
.kind = 0, .kind = 0,
@ -55,4 +69,6 @@ static item_desc items[] = {
ITEM_PROXY(ASSET_BELT_RIGHT, ASSET_BELT), ITEM_PROXY(ASSET_BELT_RIGHT, ASSET_BELT),
ITEM_PROXY(ASSET_BELT_UP, ASSET_BELT), ITEM_PROXY(ASSET_BELT_UP, ASSET_BELT),
ITEM_PROXY(ASSET_BELT_DOWN, ASSET_BELT), ITEM_PROXY(ASSET_BELT_DOWN, ASSET_BELT),
ITEM_ENT(ASSET_CHEST, 32, storage_spawn),
}; };

View File

@ -2,7 +2,7 @@
#include "compress.h" #include "compress.h"
#include "cwpack/cwpack.h" #include "cwpack/cwpack.h"
// NOTE(zaklaus): packets //NOTE(zaklaus): packets
#include "packets/pkt_00_init.h" #include "packets/pkt_00_init.h"
#include "packets/pkt_01_welcome.h" #include "packets/pkt_01_welcome.h"
@ -17,6 +17,7 @@ pkt_handler pkt_handlers[] = {
{.id = MSG_ID_01_WELCOME, .handler = pkt_01_welcome_handler}, {.id = MSG_ID_01_WELCOME, .handler = pkt_01_welcome_handler},
{.id = MSG_ID_LIBRG_UPDATE, .handler = pkt_send_librg_update_handler}, {.id = MSG_ID_LIBRG_UPDATE, .handler = pkt_send_librg_update_handler},
{.id = MSG_ID_SEND_KEYSTATE, .handler = pkt_send_keystate_handler}, {.id = MSG_ID_SEND_KEYSTATE, .handler = pkt_send_keystate_handler},
{.id = MSG_ID_SEND_BLOCKPOS, .handler = pkt_send_blockpos_handler},
{.id = MSG_ID_SWITCH_VIEWER, .handler = pkt_switch_viewer_handler}, {.id = MSG_ID_SWITCH_VIEWER, .handler = pkt_switch_viewer_handler},
}; };

View File

@ -8,6 +8,7 @@ typedef enum {
MSG_ID_01_WELCOME, MSG_ID_01_WELCOME,
MSG_ID_LIBRG_UPDATE, MSG_ID_LIBRG_UPDATE,
MSG_ID_SEND_KEYSTATE, MSG_ID_SEND_KEYSTATE,
MSG_ID_SEND_BLOCKPOS,
MSG_ID_SWITCH_VIEWER, MSG_ID_SWITCH_VIEWER,
MSG_ID_FORCE_UINT16 = UINT16_MAX, MSG_ID_FORCE_UINT16 = UINT16_MAX,
} pkt_messages; } pkt_messages;

View File

@ -16,9 +16,13 @@ pkt_desc pkt_send_keystate_desc[] = {
{ PKT_UINT(pkt_send_keystate, use) }, { PKT_UINT(pkt_send_keystate, use) },
{ PKT_UINT(pkt_send_keystate, sprint) }, { PKT_UINT(pkt_send_keystate, sprint) },
{ PKT_UINT(pkt_send_keystate, ctrl) }, { PKT_UINT(pkt_send_keystate, ctrl) },
{ PKT_UINT(pkt_send_keystate, pick) },
{ PKT_UINT(pkt_send_keystate, storage_action) },
{ PKT_UINT(pkt_send_keystate, selected_item) }, { PKT_UINT(pkt_send_keystate, selected_item) },
{ PKT_UINT(pkt_send_keystate, storage_selected_item) },
{ PKT_UINT(pkt_send_keystate, drop) }, { PKT_UINT(pkt_send_keystate, drop) },
{ PKT_UINT(pkt_send_keystate, swap) }, { PKT_UINT(pkt_send_keystate, swap) },
{ PKT_UINT(pkt_send_keystate, swap_storage) },
{ PKT_UINT(pkt_send_keystate, swap_from) }, { PKT_UINT(pkt_send_keystate, swap_from) },
{ PKT_UINT(pkt_send_keystate, swap_to) }, { PKT_UINT(pkt_send_keystate, swap_to) },
{ PKT_UINT(pkt_send_keystate, placement_num) }, { PKT_UINT(pkt_send_keystate, placement_num) },
@ -26,11 +30,23 @@ pkt_desc pkt_send_keystate_desc[] = {
{ PKT_END }, { PKT_END },
}; };
pkt_desc pkt_send_blockpos_desc[] = {
{ PKT_REAL(pkt_send_blockpos, mx) },
{ PKT_REAL(pkt_send_blockpos, my) },
{ PKT_END },
};
size_t pkt_send_keystate_send(uint16_t view_id, size_t pkt_send_keystate_send(uint16_t view_id,
game_keystate_data *data) { game_keystate_data *data) {
return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_table_encode(pkt_send_keystate_desc, PKT_STRUCT_PTR(data)), 1, view_id, NULL, 1); return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_table_encode(pkt_send_keystate_desc, PKT_STRUCT_PTR(data)), 1, view_id, NULL, 1);
} }
size_t pkt_send_blockpos_send(uint16_t view_id,
pkt_send_blockpos *data){
return pkt_world_write(MSG_ID_SEND_BLOCKPOS, pkt_table_encode(pkt_send_blockpos_desc, PKT_STRUCT_PTR(data)), 1, view_id, NULL, 1);
}
int32_t pkt_send_keystate_handler(pkt_header *header) { int32_t pkt_send_keystate_handler(pkt_header *header) {
pkt_send_keystate table; pkt_send_keystate table;
PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table))); PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table)));
@ -48,11 +64,15 @@ int32_t pkt_send_keystate_handler(pkt_header *header) {
i->use |= table.use; i->use |= table.use;
i->sprint = table.sprint; i->sprint = table.sprint;
i->ctrl = table.ctrl; i->ctrl = table.ctrl;
i->selected_item = zpl_clamp(table.selected_item, 0, ITEMS_INVENTORY_SIZE-1); i->pick |= table.pick;
i->selected_item = zpl_clamp(table.selected_item, 0, ITEMS_CONTAINER_SIZE-1);
i->storage_selected_item = zpl_clamp(table.storage_selected_item, 0, ITEMS_CONTAINER_SIZE-1);
i->drop |= table.drop; i->drop |= table.drop;
i->swap |= table.swap; i->swap |= table.swap;
i->swap_from = zpl_clamp(table.swap_from, 0, ITEMS_INVENTORY_SIZE-1); i->swap_storage |= table.swap_storage;
i->swap_to = zpl_clamp(table.swap_to, 0, ITEMS_INVENTORY_SIZE-1); i->swap_from = zpl_clamp(table.swap_from, 0, ITEMS_CONTAINER_SIZE-1);
i->swap_to = zpl_clamp(table.swap_to, 0, ITEMS_CONTAINER_SIZE-1);
i->storage_action = table.storage_action;
if (table.placement_num > 0) { if (table.placement_num > 0) {
i->num_placements = zpl_clamp(table.placement_num, 0, BUILD_MAX_PLACEMENTS); i->num_placements = zpl_clamp(table.placement_num, 0, BUILD_MAX_PLACEMENTS);
@ -67,3 +87,20 @@ int32_t pkt_send_keystate_handler(pkt_header *header) {
return 0; return 0;
} }
int32_t pkt_send_blockpos_handler(pkt_header *header) {
pkt_send_blockpos table;
PKT_IF(pkt_msg_decode(header, pkt_send_blockpos_desc, pkt_pack_desc_args(pkt_send_blockpos_desc), PKT_STRUCT_PTR(&table)));
ecs_entity_t e = network_server_get_entity(header->udata, header->view_id);
if (!world_entity_valid(e))
return 1;
Input *i = ecs_get_mut(world_ecs(), e, Input);
if (i && !i->is_blocked) {
i->bx = table.mx;
i->by = table.my;
}
return 0;
}

View File

@ -11,9 +11,15 @@ typedef struct {
uint8_t use; uint8_t use;
uint8_t sprint; uint8_t sprint;
uint8_t ctrl; uint8_t ctrl;
uint8_t pick;
// NOTE(zaklaus): inventory
uint8_t storage_action;
uint8_t selected_item; uint8_t selected_item;
uint8_t storage_selected_item;
uint8_t drop; uint8_t drop;
uint8_t swap; uint8_t swap;
uint8_t swap_storage;
uint8_t swap_from; uint8_t swap_from;
uint8_t swap_to; uint8_t swap_to;
@ -22,11 +28,22 @@ typedef struct {
item_placement placements[BUILD_MAX_PLACEMENTS]; item_placement placements[BUILD_MAX_PLACEMENTS];
} pkt_send_keystate; } pkt_send_keystate;
typedef struct {
float mx;
float my;
} pkt_send_blockpos;
typedef pkt_send_keystate game_keystate_data; typedef pkt_send_keystate game_keystate_data;
size_t pkt_send_keystate_send(uint16_t view_id, size_t pkt_send_keystate_send(uint16_t view_id,
game_keystate_data *data); game_keystate_data *data);
size_t pkt_send_blockpos_send(uint16_t view_id,
pkt_send_blockpos *data);
extern pkt_desc pkt_send_keystate_desc[]; extern pkt_desc pkt_send_keystate_desc[];
extern pkt_desc pkt_send_blockpos_desc[];
PKT_HANDLER_PROC(pkt_send_keystate_handler); PKT_HANDLER_PROC(pkt_send_keystate_handler);
PKT_HANDLER_PROC(pkt_send_blockpos_handler);

View File

@ -6,6 +6,7 @@ void platform_shutdown(void);
void platform_request_close(void); void platform_request_close(void);
float platform_frametime(void); float platform_frametime(void);
uint8_t platform_is_running(void); uint8_t platform_is_running(void);
void platform_get_block_realpos(float *x, float *y);
float platform_zoom_get(void); float platform_zoom_get(void);

View File

@ -60,16 +60,46 @@ uint8_t platform_is_running() {
return !WindowShouldClose(); return !WindowShouldClose();
} }
void platform_get_block_realpos(float *x, float *y){
camera cam = camera_get();
Vector2 mpos = GetMousePosition();
entity_view *e = game_world_view_active_get_entity(cam.ent_id);
if (!e) return;
float zoom = renderer_zoom_get();
mpos.x -= screenWidth/2.0f;
mpos.y -= screenHeight/2.0f;
cam.x += mpos.x*(1.0f/zoom);
cam.y += mpos.y*(1.0f/zoom);
cam.x = ((int32_t)cam.x / (int32_t)(WORLD_BLOCK_SIZE)) * WORLD_BLOCK_SIZE;
cam.y = ((int32_t)cam.y / (int32_t)(WORLD_BLOCK_SIZE)) * WORLD_BLOCK_SIZE;
cam.x += WORLD_BLOCK_SIZE/2.0f;
cam.y += WORLD_BLOCK_SIZE/2.0f;
if (x) *x = (float)cam.x;
if (y) *y = (float)cam.y;
}
static game_keystate_data last_input_data = {0}; static game_keystate_data last_input_data = {0};
static pkt_send_blockpos last_blockpos_data = {0};
inline static inline static
void platform_input_update_input_frame(game_keystate_data data) { void platform_input_update_input_frame(game_keystate_data data) {
float mx = 0, my = 0;
platform_get_block_realpos(&mx, &my);
if (mx != last_blockpos_data.mx || my != last_blockpos_data.my){
last_blockpos_data.mx = mx;
last_blockpos_data.my = my;
game_action_send_blockpos(mx, my);
}
// NOTE(zaklaus): Test if there are any changes // NOTE(zaklaus): Test if there are any changes
if (data.x != last_input_data.x) goto send_data; if (data.x != last_input_data.x) goto send_data;
if (data.y != last_input_data.y) goto send_data; if (data.y != last_input_data.y) goto send_data;
if (data.use != last_input_data.use) goto send_data; if (data.use != last_input_data.use) goto send_data;
if (data.sprint != last_input_data.sprint) goto send_data; if (data.sprint != last_input_data.sprint) goto send_data;
if (data.ctrl != last_input_data.ctrl) goto send_data; if (data.ctrl != last_input_data.ctrl) goto send_data;
if (data.pick != last_input_data.pick) goto send_data;
if (data.storage_action != last_input_data.storage_action) goto send_data;
if (data.selected_item != last_input_data.selected_item) goto send_data; if (data.selected_item != last_input_data.selected_item) goto send_data;
if (data.drop != last_input_data.drop) goto send_data; if (data.drop != last_input_data.drop) goto send_data;
if (data.swap != last_input_data.swap) goto send_data; if (data.swap != last_input_data.swap) goto send_data;
@ -94,7 +124,7 @@ void platform_input() {
// NOTE(zaklaus): keystate handling // NOTE(zaklaus): keystate handling
{ {
float x=0.0f, y=0.0f; float x=0.0f, y=0.0f;
uint8_t use, sprint, drop, ctrl; uint8_t use, sprint, drop, ctrl, pick;
if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) x += 1.0f; if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) x += 1.0f;
if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f; if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f;
if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f; if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f;
@ -103,7 +133,7 @@ void platform_input() {
use = IsKeyPressed(KEY_SPACE); use = IsKeyPressed(KEY_SPACE);
sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT); sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
ctrl = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL); ctrl = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);
drop = IsKeyPressed(KEY_G) || inv_drop_item; drop = IsKeyPressed(KEY_G) || player_inv.drop_item || storage_inv.drop_item;
// NOTE(zaklaus): NEW! mouse movement // NOTE(zaklaus): NEW! mouse movement
Vector2 mouse_pos = GetMousePosition(); Vector2 mouse_pos = GetMousePosition();
@ -118,6 +148,11 @@ void platform_input() {
y = -mouse_pos.y; y = -mouse_pos.y;
} }
inv_keystate *inv = (inv_is_storage_action) ? &storage_inv : &player_inv;
// NOTE(zaklaus): don't perform picking if we manipulate our inventories
pick = (inv_is_inside||inv->item_is_held) ? false : IsMouseButtonDown(MOUSE_LEFT_BUTTON);
game_keystate_data in_data = { game_keystate_data in_data = {
.x = x, .x = x,
.y = y, .y = y,
@ -126,12 +161,16 @@ void platform_input() {
.use = use, .use = use,
.sprint = sprint, .sprint = sprint,
.ctrl = ctrl, .ctrl = ctrl,
.pick = pick,
.drop = drop, .drop = drop,
.selected_item = inv_selected_item, .storage_action = inv_is_storage_action,
.swap = inv_swap, .selected_item = player_inv.selected_item,
.swap_from = inv_swap_from, .storage_selected_item = storage_inv.selected_item,
.swap_to = inv_swap_to, .swap = inv->swap,
.swap_storage = inv_swap_storage,
.swap_from = inv->swap_from,
.swap_to = inv->swap_to,
}; };
if (build_submit_placements) { if (build_submit_placements) {
@ -169,6 +208,26 @@ void platform_input() {
#endif #endif
} }
void draw_selected_item() {
camera cam = camera_get();
entity_view *oe = game_world_view_active_get_entity(cam.ent_id);
if (oe) {
// NOTE(zaklaus): sel item
entity_view *e = game_world_view_active_get_entity(oe->sel_ent);
if (e && e->kind == EKIND_DEVICE) {
renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.4f));
}else{
// NOTE(zaklaus): hover item
entity_view *e = game_world_view_active_get_entity(oe->pick_ent);
if (e && e->kind == EKIND_DEVICE) {
renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.1f));
}
}
}
}
void platform_render() { void platform_render() {
screenWidth = (uint16_t)GetScreenWidth(); screenWidth = (uint16_t)GetScreenWidth();
screenHeight = (uint16_t)GetScreenHeight(); screenHeight = (uint16_t)GetScreenHeight();
@ -184,6 +243,7 @@ void platform_render() {
{ {
profile (PROF_RENDER) { profile (PROF_RENDER) {
renderer_draw(); renderer_draw();
draw_selected_item();
} }
renderer_debug_draw(); renderer_debug_draw();
{ {

View File

@ -113,6 +113,11 @@ void DEBUG_draw_entities_low(uint64_t key, entity_view * data) {
float const h = 50; float const h = 50;
DrawRectanglePro((Rectangle){x,y,w,h}, (Vector2){w/2.0f,h/2.0f}, zpl_to_degrees(data->heading), ColorAlpha(RED, data->tran_time)); DrawRectanglePro((Rectangle){x,y,w,h}, (Vector2){w/2.0f,h/2.0f}, zpl_to_degrees(data->heading), ColorAlpha(RED, data->tran_time));
}break; }break;
case EKIND_DEVICE:{
float x = data->x - 32.f;
float y = data->y - 32.f;
DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
}break;
default:break; default:break;
} }
} }

View File

@ -0,0 +1,18 @@
#include "storage.h"
#include "entity.h"
#include "entity_view.h"
#include "world/world.h"
#include "modules/components.h"
uint64_t storage_spawn(void) {
ecs_entity_t e = entity_spawn(EKIND_DEVICE);
ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer);
*storage = (ItemContainer){0};
return (uint64_t)e;
}
void storage_despawn(uint64_t ent_id) {
entity_despawn(ent_id);
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "system.h"
uint64_t storage_spawn(void);
void storage_despawn(uint64_t id);

View File

@ -2,6 +2,7 @@
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <stddef.h> #include <stddef.h>
#include <inttypes.h> #include <inttypes.h>

View File

@ -71,8 +71,24 @@ entity_view world_build_entity_view(int64_t e) {
} }
const Input *in = ecs_get(world_ecs(), e, Input); const Input *in = ecs_get(world_ecs(), e, Input);
if (in) if (in){
view.selected_item = in->selected_item; view.selected_item = in->selected_item;
view.pick_ent = (uint64_t)in->pick_ent;
view.sel_ent = (uint64_t)in->sel_ent;
if (world_entity_valid(in->storage_ent)){
ItemContainer *ic = 0;
if ((ic = ecs_get_mut_if(world_ecs(), in->storage_ent, ItemContainer))){
view.has_storage_items = true;
for (int i = 0; i < ITEMS_CONTAINER_SIZE; i += 1) {
view.storage_items[i] = ic->items[i];
}
view.storage_selected_item = in->storage_selected_item;
}
}
}
} }
Chunk *chunk = 0; Chunk *chunk = 0;

View File

@ -252,6 +252,14 @@ int32_t worldgen_test(world_data *wld) {
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
} }
for (int i=0; i<RAND_RANGE(128, 964); i++) {
uint64_t e = item_spawn(ASSET_CHEST, 4);
Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
}
#endif #endif
return WORLD_ERROR_NONE; return WORLD_ERROR_NONE;

View File

@ -13,6 +13,7 @@ ECS_COMPONENT_DECLARE(Vehicle);
ECS_COMPONENT_DECLARE(IsInVehicle); ECS_COMPONENT_DECLARE(IsInVehicle);
ECS_COMPONENT_DECLARE(ItemDrop); ECS_COMPONENT_DECLARE(ItemDrop);
ECS_COMPONENT_DECLARE(Inventory); ECS_COMPONENT_DECLARE(Inventory);
ECS_COMPONENT_DECLARE(ItemContainer);
ECS_COMPONENT_DECLARE(DemoNPC); ECS_COMPONENT_DECLARE(DemoNPC);
ECS_COMPONENT_DECLARE(StreamInfo); ECS_COMPONENT_DECLARE(StreamInfo);
@ -32,6 +33,7 @@ void ComponentsImport(ecs_world_t *ecs) {
ECS_COMPONENT_DEFINE(ecs, IsInVehicle); ECS_COMPONENT_DEFINE(ecs, IsInVehicle);
ECS_COMPONENT_DEFINE(ecs, ItemDrop); ECS_COMPONENT_DEFINE(ecs, ItemDrop);
ECS_COMPONENT_DEFINE(ecs, Inventory); ECS_COMPONENT_DEFINE(ecs, Inventory);
ECS_COMPONENT_DEFINE(ecs, ItemContainer);
ECS_COMPONENT_DEFINE(ecs, DemoNPC); ECS_COMPONENT_DEFINE(ecs, DemoNPC);
ECS_COMPONENT_DEFINE(ecs, StreamInfo); ECS_COMPONENT_DEFINE(ecs, StreamInfo);
} }

View File

@ -7,6 +7,7 @@
#endif #endif
#define ITEMS_INVENTORY_SIZE 9 #define ITEMS_INVENTORY_SIZE 9
#define ITEMS_CONTAINER_SIZE 16
typedef struct { typedef struct {
float x; float x;
@ -32,15 +33,24 @@ typedef struct {
float y; float y;
float mx; float mx;
float my; float my;
float bx;
float by;
uint8_t use; uint8_t use;
uint8_t sprint; uint8_t sprint;
uint8_t ctrl; uint8_t ctrl;
uint8_t pick;
uint8_t is_blocked; uint8_t is_blocked;
ecs_entity_t pick_ent;
ecs_entity_t sel_ent;
// NOTE(zaklaus): inventory // NOTE(zaklaus): inventory
ecs_entity_t storage_ent;
uint8_t storage_action;
uint8_t selected_item; uint8_t selected_item;
uint8_t storage_selected_item;
uint8_t drop; uint8_t drop;
uint8_t swap; uint8_t swap;
uint8_t swap_storage;
uint8_t swap_from; uint8_t swap_from;
uint8_t swap_to; uint8_t swap_to;
@ -92,10 +102,14 @@ typedef struct {
} ItemDrop; } ItemDrop;
typedef struct { typedef struct {
ItemDrop items[ITEMS_INVENTORY_SIZE]; ItemDrop items[ITEMS_CONTAINER_SIZE];
float pickup_time; float pickup_time;
} Inventory; } Inventory;
typedef struct {
ItemDrop items[ITEMS_CONTAINER_SIZE];
} ItemContainer;
typedef struct { typedef struct {
double last_update; double last_update;
double tick_delay; double tick_delay;
@ -116,6 +130,7 @@ extern ECS_COMPONENT_DECLARE(Vehicle);
extern ECS_COMPONENT_DECLARE(IsInVehicle); extern ECS_COMPONENT_DECLARE(IsInVehicle);
extern ECS_COMPONENT_DECLARE(ItemDrop); extern ECS_COMPONENT_DECLARE(ItemDrop);
extern ECS_COMPONENT_DECLARE(Inventory); extern ECS_COMPONENT_DECLARE(Inventory);
extern ECS_COMPONENT_DECLARE(ItemContainer);
extern ECS_COMPONENT_DECLARE(DemoNPC); extern ECS_COMPONENT_DECLARE(DemoNPC);
extern ECS_COMPONENT_DECLARE(StreamInfo); extern ECS_COMPONENT_DECLARE(StreamInfo);

View File

@ -131,6 +131,7 @@ void ResetActivators(ecs_iter_t *it) {
in[i].use = false; in[i].use = false;
in[i].swap = false; in[i].swap = false;
in[i].drop = false; in[i].drop = false;
in[i].pick = false;
in[i].num_placements = 0; in[i].num_placements = 0;
} }
} }
@ -147,6 +148,43 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
float vely = blocks_get_vely(lookup.bid); float vely = blocks_get_vely(lookup.bid);
v[i].x = zpl_lerp(v[i].x, zpl_max(0.0f, zpl_abs(velx))*zpl_sign(velx), PHY_WALK_DRAG*drag*friction*safe_dt(it)); v[i].x = zpl_lerp(v[i].x, zpl_max(0.0f, zpl_abs(velx))*zpl_sign(velx), PHY_WALK_DRAG*drag*friction*safe_dt(it));
v[i].y = zpl_lerp(v[i].y, zpl_max(0.0f, zpl_abs(vely))*zpl_sign(vely), PHY_WALK_DRAG*drag*friction*safe_dt(it)); v[i].y = zpl_lerp(v[i].y, zpl_max(0.0f, zpl_abs(vely))*zpl_sign(vely), PHY_WALK_DRAG*drag*friction*safe_dt(it));
if ( zpl_abs(v[i].x) > ENTITY_ACTION_VELOCITY_THRESHOLD
|| zpl_abs(v[i].y) > ENTITY_ACTION_VELOCITY_THRESHOLD) {
entity_wake(it->entities[i]);
}
}
}
#define PLAYER_MAX_INTERACT_RANGE 35.0f
void PlayerClosestInteractable(ecs_iter_t *it){
Input *in = ecs_field(it, Input, 1);
for (int i = 0; i < it->count; ++i) {
size_t ents_count;
int64_t *ents = world_chunk_fetch_entities_realpos(in[i].bx, in[i].by, &ents_count);
ecs_entity_t closest_pick = 0;
float min_pick = ZPL_F32_MAX;
for (size_t j = 0; j < ents_count; j++) {
const Position *p2 = ecs_get(it->world, ents[j], Position);
if (!p2) continue;
float dx = p2->x - in[i].bx;
float dy = p2->y - in[i].by;
float range = zpl_sqrt(dx*dx + dy*dy);
if (range <= PLAYER_MAX_INTERACT_RANGE && range < min_pick) {
min_pick = range;
closest_pick = ents[j];
}
}
in[i].pick_ent = closest_pick;
if (in[i].pick)
in[i].sel_ent = closest_pick;
} }
} }
@ -176,11 +214,14 @@ void SystemsImport(ecs_world_t *ecs) {
ECS_SYSTEM(ecs, EnterVehicle, EcsPostUpdate, components.Input, components.Position, !components.IsInVehicle); ECS_SYSTEM(ecs, EnterVehicle, EcsPostUpdate, components.Input, components.Position, !components.IsInVehicle);
ECS_SYSTEM(ecs, LeaveVehicle, EcsPostUpdate, components.Input, components.IsInVehicle, components.Velocity); ECS_SYSTEM(ecs, LeaveVehicle, EcsPostUpdate, components.Input, components.IsInVehicle, components.Velocity);
ECS_SYSTEM(ecs, PlayerClosestInteractable, EcsPostUpdate, components.Input);
ECS_SYSTEM(ecs, PickItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle); ECS_SYSTEM(ecs, PickItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
ECS_SYSTEM(ecs, DropItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle); ECS_SYSTEM(ecs, DropItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
ECS_SYSTEM(ecs, SwapItems, EcsPostUpdate, components.Input, components.Inventory); ECS_SYSTEM(ecs, SwapItems, EcsPostUpdate, components.Input, components.Inventory);
//ECS_SYSTEM(ecs, MergeItems, EcsPostUpdate, components.Position, components.ItemDrop); //ECS_SYSTEM(ecs, MergeItems, EcsPostUpdate, components.Position, components.ItemDrop);
ECS_SYSTEM(ecs, UseItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle); ECS_SYSTEM(ecs, UseItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
ECS_SYSTEM(ecs, InspectContainers, EcsPostUpdate, components.Input, !components.IsInVehicle);
//ECS_SYSTEM(ecs, HarvestIntoContainers, EcsPostUpdate, components.ItemContainer, components.Position);
ECS_SYSTEM(ecs, ResetActivators, EcsPostUpdate, components.Input); ECS_SYSTEM(ecs, ResetActivators, EcsPostUpdate, components.Input);

View File

@ -5,6 +5,8 @@
#define ITEM_ATTRACT_RADIUS 75.0f #define ITEM_ATTRACT_RADIUS 75.0f
#define ITEM_ATTRACT_FORCE 0.63f #define ITEM_ATTRACT_FORCE 0.63f
#define ITEM_CONTAINER_REACH_RADIUS 105.0f
void PickItem(ecs_iter_t *it) { void PickItem(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 2); Position *p = ecs_field(it, Position, 2);
Inventory *inv = ecs_field(it, Inventory, 3); Inventory *inv = ecs_field(it, Inventory, 3);
@ -61,7 +63,22 @@ void DropItem(ecs_iter_t *it) {
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
if (!in[i].drop) continue; if (!in[i].drop) continue;
ItemDrop *item = &inv[i].items[in[i].selected_item]; ItemDrop *items = inv[i].items;
if (in[i].storage_action){
if (world_entity_valid(in[i].storage_ent)){
ItemContainer *ic = 0;
if ((ic = ecs_get_mut_if(it->world, in[i].storage_ent, ItemContainer))){
items = ic->items;
}else{
continue;
}
}else{
continue;
}
}
ItemDrop *item = &items[in[i].storage_action ? in[i].storage_selected_item : in[i].selected_item];
if (item->quantity <= 0) if (item->quantity <= 0)
continue; continue;
@ -143,8 +160,50 @@ void SwapItems(ecs_iter_t *it) {
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
if (!in[i].swap) continue; if (!in[i].swap) continue;
ItemDrop *to = &inv[i].items[in[i].swap_to]; ItemDrop *items = inv[i].items;
ItemDrop *from = &inv[i].items[in[i].swap_from];
if (in[i].storage_action){
if (world_entity_valid(in[i].storage_ent)){
ItemContainer *ic = 0;
if ((ic = ecs_get_mut_if(it->world, in[i].storage_ent, ItemContainer))){
items = ic->items;
}else{
continue;
}
}else{
continue;
}
}
ItemDrop *to = 0;
ItemDrop *from = 0;
if (in[i].swap_storage){
in[i].swap_storage = false;
if (in[i].storage_action){
from = &inv[i].items[in[i].swap_from];
to = &items[in[i].swap_to];
}else{
if (world_entity_valid(in[i].storage_ent)){
ItemContainer *ic = 0;
if ((ic = ecs_get_mut_if(it->world, in[i].storage_ent, ItemContainer))){
from = &ic->items[in[i].swap_from];
}else{
continue;
}
}else{
continue;
}
to = &items[in[i].swap_to];
}
}else{
from = &items[in[i].swap_from];
to = &items[in[i].swap_to];
}
ZPL_ASSERT(from && to);
uint16_t to_id = item_find(to->kind); uint16_t to_id = item_find(to->kind);
if (to == from) { if (to == from) {
@ -192,6 +251,10 @@ void UseItem(ecs_iter_t *it) {
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
if (!in[i].use && !in[i].num_placements) continue; if (!in[i].use && !in[i].num_placements) continue;
if (in[i].storage_action){
continue;
}
ItemDrop *item = &inv[i].items[in[i].selected_item]; ItemDrop *item = &inv[i].items[in[i].selected_item];
if (!item || item->quantity <= 0) continue; if (!item || item->quantity <= 0) continue;
uint16_t item_id = item_find(item->kind); uint16_t item_id = item_find(item->kind);
@ -228,3 +291,57 @@ void UseItem(ecs_iter_t *it) {
entity_wake(it->entities[i]); entity_wake(it->entities[i]);
} }
} }
void InspectContainers(ecs_iter_t *it) {
Input *in = ecs_field(it, Input, 1);
for (int i = 0; i < it->count; ++i) {
if (!in[i].pick) continue;
in[i].storage_ent = in[i].pick_ent;
}
}
void HarvestIntoContainers(ecs_iter_t *it) {
ItemContainer *in = ecs_field(it, ItemContainer, 1);
Position *p = ecs_field(it, Position, 2);
for (int i = 0; i < it->count; ++i) {
// NOTE(zaklaus): find any item
size_t ents_count;
int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2);
for (size_t j = 0; j < ents_count; j++) {
ItemDrop *drop = 0;
if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) {
const Position *p2 = ecs_get(it->world, ents[j], Position);
float dx = p2->x - p[i].x;
float dy = p2->y - p[i].y;
float range = zpl_sqrt(dx*dx + dy*dy);
if (range <= ITEM_PICK_RADIUS) {
uint16_t drop_id = item_find(drop->kind);
for (size_t k = 0; k < ITEMS_CONTAINER_SIZE; k += 1) {
ItemDrop *item = &in->items[k];
uint16_t item_id = item_find(item->kind);
if (item_id != ASSET_INVALID && (item->quantity == 0 || (item->quantity != 0 && item->kind == drop->kind)) && item->quantity < item_max_quantity(drop_id)) {
uint32_t picked_count = zpl_max(0, drop->quantity);
picked_count = zpl_clamp(picked_count, 0, item_max_quantity(drop_id) - item->quantity);
item->quantity += picked_count;
drop->quantity -= picked_count;
item->kind = drop->kind;
entity_wake(ents[j]);
entity_wake(it->entities[i]);
if (drop->quantity == 0)
item_despawn(ents[j]);
break;
}
}
}
}
}
}
}