inventory system

isolation_bkp/dynres
Dominik Madarász 2021-08-30 17:50:05 +02:00
parent a8f357184f
commit 36232e1e20
24 changed files with 582 additions and 55 deletions

View File

@ -147,6 +147,7 @@ void debug_replay_run(void) {
*pos = *p1; *pos = *p1;
ecs_set(world_ecs(), mime, Input, {0}); ecs_set(world_ecs(), mime, Input, {0});
ecs_set(world_ecs(), mime, Inventory, {0});
camera_set_follow(mime); camera_set_follow(mime);
} }
@ -167,8 +168,16 @@ void debug_replay_update(void) {
Input *i = ecs_get_mut(world_ecs(), mime, Input, NULL); Input *i = ecs_get_mut(world_ecs(), mime, Input, NULL);
i->x = r->pkt.x; i->x = r->pkt.x;
i->y = r->pkt.y; i->y = r->pkt.y;
i->mx = r->pkt.mx;
i->my = r->pkt.my;
i->use = r->pkt.use; i->use = r->pkt.use;
i->sprint = r->pkt.sprint; i->sprint = r->pkt.sprint;
i->ctrl = r->pkt.ctrl;
i->selected_item = r->pkt.selected_item;
i->drop = r->pkt.drop;
i->swap = r->pkt.swap;
i->swap_from = r->pkt.swap_from;
i->swap_to = r->pkt.swap_to;
}break; }break;
case RPKIND_SPAWN_CAR: { case RPKIND_SPAWN_CAR: {
ecs_entity_t e = vehicle_spawn(); ecs_entity_t e = vehicle_spawn();

View File

@ -72,18 +72,6 @@ typedef struct debug_item {
debug_draw_result (*proc)(struct debug_item*, float, float); debug_draw_result (*proc)(struct debug_item*, float, float);
} debug_item; } debug_item;
typedef enum {
DAREA_OUTSIDE,
DAREA_HOVER,
DAREA_HELD,
DAREA_PRESS,
DAREA_FORCE_UINT8 = UINT8_MAX
} debug_area_status;
debug_area_status check_mouse_area(float xpos, float ypos, float w, float h);
bool is_btn_pressed(float xpos, float ypos, float w, float h, Color *color);
static void UIDrawText(const char *text, float posX, float posY, int fontSize, Color color); static void UIDrawText(const char *text, float posX, float posY, int fontSize, Color color);
static int UIMeasureText(const char *text, int fontSize); static int UIMeasureText(const char *text, int fontSize);

View File

@ -1,4 +1,17 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#include "raylib.h"
void debug_draw(void); void debug_draw(void);
typedef enum {
DAREA_OUTSIDE,
DAREA_HOVER,
DAREA_HELD,
DAREA_PRESS,
DAREA_FORCE_UINT8 = UINT8_MAX
} debug_area_status;
debug_area_status check_mouse_area(float xpos, float ypos, float w, float h);
bool is_btn_pressed(float xpos, float ypos, float w, float h, Color *color);

View File

@ -63,7 +63,7 @@ ActPlaceIceRink(void) {
for (int y = 0; y < 100; y++) { for (int y = 0; y < 100; y++) {
for (int x = 0; x < 100; x++) { for (int x = 0; x < 100; x++) {
world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f); world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f);
world_chunk_replace_outer_block(world_ecs(), l.chunk_id, l.id, watr_id); world_chunk_replace_outer_block(l.chunk_id, l.id, watr_id);
} }
} }
@ -79,7 +79,7 @@ ActEraseWorldChanges(void) {
for (int y = 0; y < 100; y++) { for (int y = 0; y < 100; y++) {
for (int x = 0; x < 100; x++) { for (int x = 0; x < 100; x++) {
world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f); world_block_lookup l = world_block_from_realpos((p->x - (x*bs)/2.0f), p->y - (y*bs)/2.0f);
world_chunk_replace_outer_block(world_ecs(), l.chunk_id, l.id, 0); world_chunk_replace_outer_block(l.chunk_id, l.id, 0);
} }
} }

View File

@ -26,8 +26,14 @@ pkt_desc pkt_entity_view_desc[] = {
{ PKT_KEEP_IF(entity_view, kind, EKIND_VEHICLE, 1) }, // NOTE(zaklaus): keep for vehicles { PKT_KEEP_IF(entity_view, kind, EKIND_VEHICLE, 1) }, // NOTE(zaklaus): keep for vehicles
{ PKT_HALF(entity_view, heading) }, { PKT_HALF(entity_view, heading) },
{ PKT_KEEP_IF(entity_view, kind, EKIND_ITEM, 1) }, { PKT_KEEP_IF(entity_view, kind, EKIND_ITEM, 2) },
{ PKT_UINT(entity_view, asset) }, { PKT_UINT(entity_view, asset) },
{ PKT_UINT(entity_view, quantity) },
{ PKT_KEEP_IF(entity_view, has_items, true, 3) },
{ PKT_UINT(entity_view, has_items) },
{ PKT_ARRAY(entity_view, items) },
{ PKT_UINT(entity_view, selected_item) },
{ PKT_END }, { PKT_END },
}; };

View File

@ -1,6 +1,9 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#include "assets.h" #include "assets.h"
#include "items.h"
#include "modules/components.h"
#define ZPL_PICO #define ZPL_PICO
#include "zpl.h" #include "zpl.h"
@ -57,6 +60,12 @@ typedef struct entity_view {
// NOTE(zaklaus): items, ... // NOTE(zaklaus): items, ...
asset_id asset; asset_id asset;
uint32_t quantity;
// NOTE(zaklaus): inventory
uint8_t has_items;
ItemDrop items[ITEMS_INVENTORY_SIZE];
uint8_t selected_item;
// NOTE(zaklaus): internals // NOTE(zaklaus): internals
uint8_t layer_id; uint8_t layer_id;

View File

@ -92,6 +92,10 @@ void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_vie
entity_view_map(&active_viewer->entities, map_proc); entity_view_map(&active_viewer->entities, map_proc);
} }
entity_view *game_world_view_active_get_entity(uint64_t ent_id) {
return entity_view_get(&active_viewer->entities, ent_id);
}
void game_world_view_set_active(world_view *view) { void game_world_view_set_active(world_view *view) {
active_viewer = view; active_viewer = view;
camera_set_follow(view->owner_id); camera_set_follow(view->owner_id);
@ -170,8 +174,19 @@ void game_render() {
platform_render(); platform_render();
} }
void game_action_send_keystate(float x, float y, uint8_t use, uint8_t sprint) { void game_action_send_keystate(float x,
pkt_send_keystate_send(active_viewer->view_id, x, y, use, sprint); float y,
float mx,
float my,
uint8_t use,
uint8_t sprint,
uint8_t ctrl,
uint8_t drop,
uint8_t selected_item,
uint8_t swap,
uint8_t swap_from,
uint8_t swap_to) {
pkt_send_keystate_send(active_viewer->view_id, x, y, mx, my, use, sprint, ctrl, drop, selected_item, swap, swap_from, swap_to);
} }
#define GAME_ENT_REMOVAL_TIME 10000 #define GAME_ENT_REMOVAL_TIME 10000

View File

@ -28,7 +28,19 @@ void game_world_view_set_active_by_idx(uint16_t idx);
void game_world_view_set_active(world_view *view); void game_world_view_set_active(world_view *view);
void game_world_view_cycle_active(int8_t dir); void game_world_view_cycle_active(int8_t dir);
void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value)); void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value));
entity_view *game_world_view_active_get_entity(uint64_t ent_id);
void game_world_cleanup_entities(void); void game_world_cleanup_entities(void);
//~ NOTE(zaklaus): viewer -> host actions //~ NOTE(zaklaus): viewer -> host actions
void game_action_send_keystate(float x, float y, uint8_t use, uint8_t sprint); void game_action_send_keystate(float x,
float y,
float mx,
float my,
uint8_t use,
uint8_t sprint,
uint8_t ctrl,
uint8_t drop,
uint8_t selected_item,
uint8_t swap,
uint8_t swap_from,
uint8_t swap_to);

View File

@ -0,0 +1,92 @@
#include "items.h"
static uint8_t inv_selected_item = 0;
static bool inv_drop_item = false;
static 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;
void inventory_draw() {
inv_drop_item = false;
inv_swap = false;
camera cam = camera_get();
entity_view *e = game_world_view_active_get_entity(cam.ent_id);
if (!e || !e->has_items) return;
if (IsKeyPressed(KEY_TAB)) {
inv_is_open = !inv_is_open;
}
if (!inv_is_open) return;
float sx = screenWidth/2.0f + 128;
float sy = screenHeight/2.0f - 96;
float x = sx;
float y = sy;
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) {
asset_id asset = item_get_asset(item->kind);
DrawTexturePro(GetSpriteTexture2D(assets_find(asset)), 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;
asset_id asset = item_get_asset(item_find(inv_held_item.kind));
DrawTexturePro(GetSpriteTexture2D(assets_find(asset)), 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

@ -2,9 +2,15 @@
#include "entity.h" #include "entity.h"
#include "entity_view.h" #include "entity_view.h"
#include "world/world.h" #include "world/world.h"
#include "world/blocks.h"
#include "modules/components.h" #include "modules/components.h"
#include "zpl.h"
#include "items_list.c"
#define ITEMS_COUNT (sizeof(items)/sizeof(item_desc))
uint64_t item_spawn(item_kind kind, uint32_t qty) { uint64_t item_spawn(item_kind kind, uint32_t qty) {
ecs_entity_t e = entity_spawn(EKIND_ITEM); ecs_entity_t e = entity_spawn(EKIND_ITEM);
@ -17,15 +23,42 @@ uint64_t item_spawn(item_kind kind, uint32_t qty) {
return (uint64_t)e; return (uint64_t)e;
} }
uint16_t item_find(item_kind kind) {
for (uint32_t i=0; i<ITEMS_COUNT; i++) {
if (items[i].kind == kind)
return i;
}
return ITEMS_INVALID;
}
void item_use(ecs_world_t *ecs, ItemDrop *it, Position p) {
(void)ecs;
uint16_t item_id = item_find(it->kind);
item_desc *desc = &items[item_id];
switch (item_get_usage(item_id)) {
case UKIND_PLACE:{
world_block_lookup l = world_block_from_realpos(p.x, p.y);
world_chunk_replace_outer_block(l.chunk_id, l.id, blocks_find(desc->place.biome, desc->place.kind));
it->quantity--;
}break;
}
}
void item_despawn(uint64_t id) { void item_despawn(uint64_t id) {
entity_despawn(id); entity_despawn(id);
} }
asset_id item_get_asset(item_kind kind) { uint32_t item_max_quantity(uint16_t id) {
switch (kind) { ZPL_ASSERT(id >= 0 && id < ITEMS_COUNT);
case IKIND_DEMO_ICEMAKER: return ASSET_DEMO_ICEMAKER; return items[id].max_quantity;
} }
ZPL_PANIC("unreachable code"); asset_id item_get_asset(uint16_t id) {
return 0; ZPL_ASSERT(id >= 0 && id < ITEMS_COUNT);
return items[id].asset;
}
item_usage item_get_usage(uint16_t id) {
ZPL_ASSERT(id >= 0 && id < ITEMS_COUNT);
return items[id].usage;
} }

View File

@ -1,14 +1,46 @@
#pragma once #pragma once
#include "system.h" #include "system.h"
#include "assets.h" #include "assets.h"
#include "world/blocks.h"
#include "modules/components.h"
#define ITEMS_INVALID 0xFF
typedef enum { typedef enum {
IKIND_DEMO_ICEMAKER, IKIND_DEMO_ICEMAKER,
} item_kind; } item_kind;
typedef enum {
UKIND_PLACE,
} item_usage;
typedef struct {
item_kind kind;
item_usage usage;
asset_id asset;
uint32_t max_quantity;
// NOTE(zaklaus): usage data
union {
struct {
block_biome biome;
block_kind kind;
} place;
};
} item_desc;
// NOTE(zaklaus): item drops
uint64_t item_spawn(item_kind kind, uint32_t qty); uint64_t item_spawn(item_kind kind, uint32_t qty);
void item_despawn(uint64_t id); void item_despawn(uint64_t id);
// NOTE(zaklaus): items
uint16_t item_find(item_kind kind);
void item_use(ecs_world_t *ecs, ItemDrop *it, Position p);
uint32_t item_max_quantity(uint16_t id);
item_usage item_get_usage(uint16_t id);
// NOTE(zaklaus): client // NOTE(zaklaus): client
asset_id item_get_asset(item_kind kind); asset_id item_get_asset(uint16_t id);

View File

@ -0,0 +1,15 @@
#include "items.h"
static item_desc items[] = {
{
.kind = IKIND_DEMO_ICEMAKER,
.usage = UKIND_PLACE,
.asset = ASSET_DEMO_ICEMAKER,
.max_quantity = 4,
.place = {
.biome = BLOCK_BIOME_DEV,
.kind = BLOCK_KIND_WATER,
}
}
};

View File

@ -9,17 +9,33 @@
pkt_desc pkt_send_keystate_desc[] = { pkt_desc pkt_send_keystate_desc[] = {
{ PKT_REAL(pkt_send_keystate, x) }, { PKT_REAL(pkt_send_keystate, x) },
{ PKT_REAL(pkt_send_keystate, y) }, { PKT_REAL(pkt_send_keystate, y) },
{ PKT_REAL(pkt_send_keystate, mx) },
{ PKT_REAL(pkt_send_keystate, my) },
{ 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, selected_item) },
{ PKT_UINT(pkt_send_keystate, drop) },
{ PKT_UINT(pkt_send_keystate, swap) },
{ PKT_UINT(pkt_send_keystate, swap_from) },
{ PKT_UINT(pkt_send_keystate, swap_to) },
{ PKT_END }, { PKT_END },
}; };
size_t pkt_send_keystate_send(uint16_t view_id, size_t pkt_send_keystate_send(uint16_t view_id,
float x, float x,
float y, float y,
float mx,
float my,
uint8_t use, uint8_t use,
uint8_t sprint) { uint8_t sprint,
pkt_send_keystate table = { .x = x, .y = y, .use = use, .sprint = sprint }; uint8_t ctrl,
uint8_t drop,
uint8_t selected_item,
uint8_t swap,
uint8_t swap_from,
uint8_t swap_to) {
pkt_send_keystate table = { .x = x, .y = y, .mx = mx, .my = my, .use = use, .sprint = sprint, .ctrl = ctrl, .drop = drop, .selected_item = selected_item, .swap = swap, .swap_from = swap_from, .swap_to = swap_to };
return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_send_keystate_encode(&table), 1, view_id, NULL); return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_send_keystate_encode(&table), 1, view_id, NULL);
} }
@ -39,8 +55,16 @@ int32_t pkt_send_keystate_handler(pkt_header *header) {
if (i && !i->is_blocked) { if (i && !i->is_blocked) {
i->x = table.x; i->x = table.x;
i->y = table.y; i->y = table.y;
i->mx = table.mx;
i->my = table.my;
i->use = table.use; i->use = table.use;
i->sprint = table.sprint; i->sprint = table.sprint;
i->ctrl = table.ctrl;
i->selected_item = zpl_clamp(table.selected_item, 0, ITEMS_INVENTORY_SIZE-1);
i->drop = table.drop;
i->swap = table.swap;
i->swap_from = zpl_clamp(table.swap_from, 0, ITEMS_INVENTORY_SIZE-1);
i->swap_to = zpl_clamp(table.swap_to, 0, ITEMS_INVENTORY_SIZE-1);
debug_replay_record_keystate(table); debug_replay_record_keystate(table);
} }

View File

@ -5,14 +5,30 @@
typedef struct { typedef struct {
float x; float x;
float y; float y;
float mx;
float my;
uint8_t use; uint8_t use;
uint8_t sprint; uint8_t sprint;
uint8_t ctrl;
uint8_t selected_item;
uint8_t drop;
uint8_t swap;
uint8_t swap_from;
uint8_t swap_to;
} pkt_send_keystate; } pkt_send_keystate;
size_t pkt_send_keystate_send(uint16_t view_id, size_t pkt_send_keystate_send(uint16_t view_id,
float x, float x,
float y, float y,
float mx,
float my,
uint8_t use, uint8_t use,
uint8_t sprint); uint8_t sprint,
uint8_t ctrl,
uint8_t drop,
uint8_t selected_item,
uint8_t swap,
uint8_t swap_from,
uint8_t swap_to);
size_t pkt_send_keystate_encode(pkt_send_keystate *table); size_t pkt_send_keystate_encode(pkt_send_keystate *table);
extern pkt_desc pkt_send_keystate_desc[]; extern pkt_desc pkt_send_keystate_desc[];

View File

@ -21,6 +21,9 @@ static bool request_shutdown;
#define GFX_KIND 2 #define GFX_KIND 2
#include "renderer_bridge.c" #include "renderer_bridge.c"
// NOTE(zaklaus): add-ins
#include "gui/inventory.c"
void platform_init() { void platform_init() {
InitWindow(screenWidth, screenHeight, "eco2d"); InitWindow(screenWidth, screenHeight, "eco2d");
SetWindowState(FLAG_WINDOW_UNDECORATED|FLAG_WINDOW_MAXIMIZED|FLAG_WINDOW_RESIZABLE|FLAG_MSAA_4X_HINT); SetWindowState(FLAG_WINDOW_UNDECORATED|FLAG_WINDOW_MAXIMIZED|FLAG_WINDOW_RESIZABLE|FLAG_MSAA_4X_HINT);
@ -63,7 +66,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; uint8_t use, sprint, drop, ctrl;
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;
@ -71,20 +74,23 @@ 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);
drop = IsKeyPressed(KEY_G) || inv_drop_item;
// NOTE(zaklaus): NEW! mouse movement // NOTE(zaklaus): NEW! mouse movement
Vector2 mouse_pos = GetMousePosition();
mouse_pos.x /= screenWidth;
mouse_pos.y /= screenHeight;
mouse_pos.x -= 0.5f;
mouse_pos.y -= 0.5f;
mouse_pos = Vector2Normalize(mouse_pos);
if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) { if (IsMouseButtonDown(MOUSE_RIGHT_BUTTON)) {
Vector2 mouse_pos = GetMousePosition();
mouse_pos.x /= screenWidth;
mouse_pos.y /= screenHeight;
mouse_pos.x -= 0.5f;
mouse_pos.y -= 0.5f;
mouse_pos = Vector2Normalize(mouse_pos);
x = mouse_pos.x; x = mouse_pos.x;
y = -mouse_pos.y; y = -mouse_pos.y;
} }
game_action_send_keystate(x, y, use, sprint); game_action_send_keystate(x, y, mouse_pos.x, mouse_pos.y, use, sprint, ctrl, drop, inv_selected_item, inv_swap, inv_swap_from, inv_swap_to);
} }
// NOTE(zaklaus): cycle through viewers // NOTE(zaklaus): cycle through viewers
@ -126,6 +132,10 @@ void platform_render() {
renderer_draw(); renderer_draw();
} }
renderer_debug_draw(); renderer_debug_draw();
{
// NOTE(zaklaus): add-ins
inventory_draw();
}
debug_draw(); debug_draw();
display_conn_status(); display_conn_status();
} }

View File

@ -22,6 +22,7 @@ uint64_t player_spawn(char *name) {
ecs_set_name(world_ecs(), e, name); ecs_set_name(world_ecs(), e, name);
ecs_set(world_ecs(), e, ClientInfo, {0}); ecs_set(world_ecs(), e, ClientInfo, {0});
ecs_set(world_ecs(), e, Input, {0}); ecs_set(world_ecs(), e, Input, {0});
ecs_set(world_ecs(), e, Inventory, {0});
ecs_set(world_ecs(), e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP}); ecs_set(world_ecs(), e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP});
ecs_add(world_ecs(), e, Player); ecs_add(world_ecs(), e, Player);

View File

@ -56,6 +56,16 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time)); DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time));
DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing); DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing);
DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time)); DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time));
if (data->has_items) {
float ix = data->x;
float iy = data->y;
if (data->items[data->selected_item].quantity > 0) {
item_kind it_kind = data->items[data->selected_item].kind;
uint16_t it_id = item_find(it_kind);
DrawTexturePro(GetSpriteTexture2D(assets_find(item_get_asset(it_id))), ASSET_SRC_RECT(), ((Rectangle){ix, iy, 32, 32}), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
}
}
}break; }break;
case EKIND_MACRO_BOT: { case EKIND_MACRO_BOT: {
float x = data->x; float x = data->x;
@ -70,6 +80,7 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
float x = data->x - 32.f; float x = data->x - 32.f;
float y = data->y - 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)); DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f);
}break; }break;
default:break; default:break;
} }

View File

@ -55,6 +55,21 @@ entity_view world_build_entity_view(int64_t e) {
if (ecs_get(world_ecs(), e, ItemDrop)) { if (ecs_get(world_ecs(), e, ItemDrop)) {
ItemDrop const* dr = ecs_get(world_ecs(), e, ItemDrop); ItemDrop const* dr = ecs_get(world_ecs(), e, ItemDrop);
view.asset = item_get_asset(dr->kind); view.asset = item_get_asset(dr->kind);
view.quantity = dr->quantity;
const Input *in = ecs_get(world_ecs(), e, Input);
if (in)
view.selected_item = in->selected_item;
}
Inventory *inv = 0;
if ((inv = ecs_get_mut_if(world_ecs(), e, Inventory))) {
view.has_items = true;
for (int i = 0; i < ITEMS_INVENTORY_SIZE; i += 1) {
view.items[i] = inv->items[i];
}
} }
Chunk *chpos = 0; Chunk *chpos = 0;
@ -305,9 +320,16 @@ uint32_t world_buf(uint8_t const **ptr, uint32_t *width) {
} }
ecs_world_t * world_ecs() { ecs_world_t * world_ecs() {
if (world.ecs_stage != NULL) {
return world.ecs_stage;
}
return world.ecs; return world.ecs;
} }
void world_set_stage(ecs_world_t *ecs) {
world.ecs_stage = ecs;
}
librg_world *world_tracker() { librg_world *world_tracker() {
return world.tracker; return world.tracker;
} }
@ -391,32 +413,32 @@ int64_t world_chunk_from_entity(ecs_entity_t id) {
return librg_entity_chunk_get(world.tracker, id); return librg_entity_chunk_get(world.tracker, id);
} }
void world_chunk_replace_block(ecs_world_t *ecs, int64_t id, uint16_t block_idx, uint8_t block_id) { void world_chunk_replace_block(int64_t id, uint16_t block_idx, uint8_t block_id) {
ZPL_ASSERT(block_idx >= 0 && block_idx < zpl_square(world.chunk_size)); ZPL_ASSERT(block_idx >= 0 && block_idx < zpl_square(world.chunk_size));
world.block_mapping[id][block_idx] = block_id; world.block_mapping[id][block_idx] = block_id;
world_chunk_mark_dirty(ecs, world.chunk_mapping[id]); world_chunk_mark_dirty(world.chunk_mapping[id]);
} }
void world_chunk_replace_outer_block(ecs_world_t *ecs, int64_t id, uint16_t block_idx, uint8_t block_id) { void world_chunk_replace_outer_block(int64_t id, uint16_t block_idx, uint8_t block_id) {
ZPL_ASSERT(block_idx >= 0 && block_idx < zpl_square(world.chunk_size)); ZPL_ASSERT(block_idx >= 0 && block_idx < zpl_square(world.chunk_size));
world.outer_block_mapping[id][block_idx] = block_id; world.outer_block_mapping[id][block_idx] = block_id;
world_chunk_mark_dirty(ecs, world.chunk_mapping[id]); world_chunk_mark_dirty(world.chunk_mapping[id]);
} }
uint8_t *world_chunk_get_blocks(int64_t id) { uint8_t *world_chunk_get_blocks(int64_t id) {
return world.block_mapping[id]; return world.block_mapping[id];
} }
void world_chunk_mark_dirty(ecs_world_t *ecs, ecs_entity_t e) { void world_chunk_mark_dirty(ecs_entity_t e) {
bool was_added=false; bool was_added=false;
Chunk *chunk = ecs_get_mut(ecs, e, Chunk, &was_added); Chunk *chunk = ecs_get_mut(world_ecs(), e, Chunk, &was_added);
ZPL_ASSERT(!was_added); ZPL_ASSERT(!was_added);
if (chunk) chunk->is_dirty = true; if (chunk) chunk->is_dirty = true;
} }
uint8_t world_chunk_is_dirty(ecs_world_t *ecs, ecs_entity_t e) { uint8_t world_chunk_is_dirty(ecs_entity_t e) {
bool was_added=false; bool was_added=false;
Chunk *chunk = ecs_get_mut(ecs, e, Chunk, &was_added); Chunk *chunk = ecs_get_mut(world_ecs(), e, Chunk, &was_added);
ZPL_ASSERT(!was_added); ZPL_ASSERT(!was_added);
if (chunk) return chunk->is_dirty; if (chunk) return chunk->is_dirty;
return false; return false;
@ -445,5 +467,5 @@ int64_t *world_chunk_query_entities(int64_t e, size_t *ents_len, int8_t radius)
uint8_t world_entity_valid(ecs_entity_t e) { uint8_t world_entity_valid(ecs_entity_t e) {
if (!e) return false; if (!e) return false;
return ecs_is_alive(world.ecs, e); return ecs_is_alive(world_ecs(), e);
} }

View File

@ -38,6 +38,7 @@ typedef struct {
uint64_t tracker_update[3]; uint64_t tracker_update[3];
uint8_t active_layer_id; uint8_t active_layer_id;
ecs_world_t *ecs; ecs_world_t *ecs;
ecs_world_t *ecs_stage;
ecs_query_t *ecs_update; ecs_query_t *ecs_update;
ecs_entity_t *chunk_mapping; ecs_entity_t *chunk_mapping;
librg_world *tracker; librg_world *tracker;
@ -54,7 +55,8 @@ int32_t world_read(void* data, uint32_t datalen, void *udata);
int32_t world_write(pkt_header *pkt, void *udata); int32_t world_write(pkt_header *pkt, void *udata);
uint32_t world_buf(uint8_t const **ptr, uint32_t *width); uint32_t world_buf(uint8_t const **ptr, uint32_t *width);
ecs_world_t *world_ecs(void); // TODO(zaklaus): add staging support ecs_world_t *world_ecs(void);
void world_set_stage(ecs_world_t *ecs);
librg_world *world_tracker(void); librg_world *world_tracker(void);
uint16_t world_chunk_size(void); uint16_t world_chunk_size(void);
@ -74,11 +76,11 @@ world_block_lookup world_block_from_realpos(float x, float y);
world_block_lookup world_block_from_index(int64_t id, uint16_t block_idx); world_block_lookup world_block_from_index(int64_t id, uint16_t block_idx);
int64_t world_chunk_from_realpos(float x, float y); int64_t world_chunk_from_realpos(float x, float y);
int64_t world_chunk_from_entity(ecs_entity_t id); int64_t world_chunk_from_entity(ecs_entity_t id);
void world_chunk_replace_block(ecs_world_t *ecs, int64_t id, uint16_t block_idx, uint8_t block_id); void world_chunk_replace_block(int64_t id, uint16_t block_idx, uint8_t block_id);
void world_chunk_replace_outer_block(ecs_world_t *ecs, int64_t id, uint16_t block_idx, uint8_t block_id); void world_chunk_replace_outer_block(int64_t id, uint16_t block_idx, uint8_t block_id);
uint8_t *world_chunk_get_blocks(int64_t id); uint8_t *world_chunk_get_blocks(int64_t id);
void world_chunk_mark_dirty(ecs_world_t *ecs, ecs_entity_t e); void world_chunk_mark_dirty(ecs_entity_t e);
uint8_t world_chunk_is_dirty(ecs_world_t *ecs, ecs_entity_t e); uint8_t world_chunk_is_dirty(ecs_entity_t e);
// NOTE(zaklaus): Uses locally persistent buffer !! // NOTE(zaklaus): Uses locally persistent buffer !!
int64_t *world_chunk_fetch_entities(librg_chunk chunk_id, size_t *ents_len); int64_t *world_chunk_fetch_entities(librg_chunk chunk_id, size_t *ents_len);

View File

@ -12,6 +12,7 @@ ECS_COMPONENT_DECLARE(Classify);
ECS_COMPONENT_DECLARE(Vehicle); 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_TAG_DECLARE(EcsActor); ECS_TAG_DECLARE(EcsActor);
ECS_TAG_DECLARE(EcsDemoNPC); ECS_TAG_DECLARE(EcsDemoNPC);
ECS_TYPE_DECLARE(Player); ECS_TYPE_DECLARE(Player);
@ -37,6 +38,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_TAG_DEFINE(ecs, Walking); ECS_TAG_DEFINE(ecs, Walking);
ECS_TAG_DEFINE(ecs, Flying); ECS_TAG_DEFINE(ecs, Flying);
@ -59,6 +61,7 @@ void ComponentsImport(ecs_world_t *ecs) {
ECS_SET_COMPONENT(Vehicle); ECS_SET_COMPONENT(Vehicle);
ECS_SET_COMPONENT(IsInVehicle); ECS_SET_COMPONENT(IsInVehicle);
ECS_SET_COMPONENT(ItemDrop); ECS_SET_COMPONENT(ItemDrop);
ECS_SET_COMPONENT(Inventory);
ECS_SET_ENTITY(Walking); ECS_SET_ENTITY(Walking);
ECS_SET_ENTITY(Flying); ECS_SET_ENTITY(Flying);
ECS_SET_ENTITY(EcsActor); ECS_SET_ENTITY(EcsActor);

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "flecs/flecs.h" #include "flecs/flecs.h"
#include "flecs/flecs_meta.h" #include "flecs/flecs_meta.h"
#include "items.h"
//NOTE(zaklaus): custom macro to define meta components outside the current scope //NOTE(zaklaus): custom macro to define meta components outside the current scope
@ -16,6 +15,8 @@ ecs_new_meta(world, ecs_entity(T), &__##T##__);
(ecs_get(world, entity, component) ? ecs_get_mut(world, entity, component, NULL) : NULL) (ecs_get(world, entity, component) ? ecs_get_mut(world, entity, component, NULL) : NULL)
#endif #endif
#define ITEMS_INVENTORY_SIZE 9
ECS_STRUCT(Vector2D, { ECS_STRUCT(Vector2D, {
float x; float x;
float y; float y;
@ -38,9 +39,19 @@ ECS_ALIAS(Vector2D, Velocity);
ECS_STRUCT(Input, { ECS_STRUCT(Input, {
float x; float x;
float y; float y;
float mx;
float my;
uint8_t use; uint8_t use;
uint8_t sprint; uint8_t sprint;
uint8_t ctrl;
uint8_t is_blocked; uint8_t is_blocked;
// NOTE(zaklaus): inventory
uint8_t selected_item;
uint8_t drop;
uint8_t swap;
uint8_t swap_from;
uint8_t swap_to;
}); });
ECS_STRUCT(ClientInfo, { ECS_STRUCT(ClientInfo, {
@ -78,10 +89,15 @@ typedef struct {
} IsInVehicle; } IsInVehicle;
typedef struct { typedef struct {
item_kind kind; uint16_t kind;
uint32_t quantity; uint32_t quantity;
} ItemDrop; } ItemDrop;
typedef struct {
ItemDrop items[ITEMS_INVENTORY_SIZE];
float pickup_time;
} Inventory;
ECS_COMPONENT_EXTERN(Chunk); ECS_COMPONENT_EXTERN(Chunk);
ECS_COMPONENT_EXTERN(Position); ECS_COMPONENT_EXTERN(Position);
ECS_COMPONENT_EXTERN(Vector2D); ECS_COMPONENT_EXTERN(Vector2D);
@ -94,6 +110,7 @@ ECS_COMPONENT_EXTERN(Classify);
ECS_COMPONENT_EXTERN(Vehicle); ECS_COMPONENT_EXTERN(Vehicle);
ECS_COMPONENT_EXTERN(IsInVehicle); ECS_COMPONENT_EXTERN(IsInVehicle);
ECS_COMPONENT_EXTERN(ItemDrop); ECS_COMPONENT_EXTERN(ItemDrop);
ECS_COMPONENT_EXTERN(Inventory);
ECS_TAG_EXTERN(EcsActor); ECS_TAG_EXTERN(EcsActor);
ECS_TAG_EXTERN(EcsDemoNPC); ECS_TAG_EXTERN(EcsDemoNPC);
ECS_TYPE_EXTERN(Player); ECS_TYPE_EXTERN(Player);
@ -116,6 +133,7 @@ typedef struct {
ECS_DECLARE_COMPONENT(Vehicle); ECS_DECLARE_COMPONENT(Vehicle);
ECS_DECLARE_COMPONENT(IsInVehicle); ECS_DECLARE_COMPONENT(IsInVehicle);
ECS_DECLARE_COMPONENT(ItemDrop); ECS_DECLARE_COMPONENT(ItemDrop);
ECS_DECLARE_COMPONENT(Inventory);
ECS_DECLARE_ENTITY(EcsActor); ECS_DECLARE_ENTITY(EcsActor);
ECS_DECLARE_ENTITY(EcsDemoNPC); ECS_DECLARE_ENTITY(EcsDemoNPC);
ECS_DECLARE_TYPE(Player); ECS_DECLARE_TYPE(Player);
@ -139,6 +157,7 @@ ECS_IMPORT_COMPONENT(handles, Classify);\
ECS_IMPORT_COMPONENT(handles, Vehicle);\ ECS_IMPORT_COMPONENT(handles, Vehicle);\
ECS_IMPORT_COMPONENT(handles, IsInVehicle);\ ECS_IMPORT_COMPONENT(handles, IsInVehicle);\
ECS_IMPORT_COMPONENT(handles, ItemDrop);\ ECS_IMPORT_COMPONENT(handles, ItemDrop);\
ECS_IMPORT_COMPONENT(handles, Inventory);\
ECS_IMPORT_TYPE(handles, Player);\ ECS_IMPORT_TYPE(handles, Player);\
ECS_IMPORT_TYPE(handles, Builder);\ ECS_IMPORT_TYPE(handles, Builder);\
ECS_IMPORT_TYPE(handles, Movement);\ ECS_IMPORT_TYPE(handles, Movement);\

View File

@ -14,6 +14,7 @@
#include "source/system_onfoot.c" #include "source/system_onfoot.c"
#include "source/system_demo.c" #include "source/system_demo.c"
#include "source/system_vehicle.c" #include "source/system_vehicle.c"
#include "source/system_items.c"
inline float physics_correction(float x, float vx, float bounce) { inline float physics_correction(float x, float vx, float bounce) {
float r = (((zpl_max(0.0f, (WORLD_BLOCK_SIZE/2.0f) - zpl_abs(x))*zpl_sign(x)))*(WORLD_BLOCK_SIZE/2.0f)); float r = (((zpl_max(0.0f, (WORLD_BLOCK_SIZE/2.0f) - zpl_abs(x))*zpl_sign(x)))*(WORLD_BLOCK_SIZE/2.0f));
@ -131,9 +132,19 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
} }
} }
void EnableWorldEdit(ecs_iter_t *it) {
world_set_stage(it->world);
}
void DisableWorldEdit(ecs_iter_t *it) {
(void)it;
world_set_stage(NULL);
}
void SystemsImport(ecs_world_t *ecs) { void SystemsImport(ecs_world_t *ecs) {
ECS_MODULE(ecs, Systems); ECS_MODULE(ecs, Systems);
ECS_SYSTEM(ecs, EnableWorldEdit, EcsOnLoad);
ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, components.Input, components.Velocity, components.Position, !components.IsInVehicle); ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, components.Input, components.Velocity, components.Position, !components.IsInVehicle);
ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.EcsDemoNPC); ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.EcsDemoNPC);
@ -146,10 +157,16 @@ 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, DemoPlaceIceBlock, EcsPostUpdate, components.Input, components.Position, !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, SwapItems, EcsPostUpdate, components.Input, components.Inventory);
ECS_SYSTEM(ecs, UseItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
ECS_SYSTEM(ecs, UpdateTrackerPos, EcsPostUpdate, components.Position, components.Velocity); ECS_SYSTEM(ecs, UpdateTrackerPos, EcsPostUpdate, components.Position, components.Velocity);
ECS_SYSTEM(ecs, ClearVehicle, EcsUnSet, components.Vehicle); ECS_SYSTEM(ecs, ClearVehicle, EcsUnSet, components.Vehicle);
ECS_SYSTEM(ecs, DisableWorldEdit, EcsPostUpdate);
} }

View File

@ -20,7 +20,7 @@ void DemoPlaceIceBlock(ecs_iter_t *it) {
if (in[i].use) { if (in[i].use) {
in[i].use = false; in[i].use = false;
world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y); world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y);
world_chunk_replace_outer_block(it->world, l.chunk_id, l.id, watr_id); world_chunk_replace_outer_block(l.chunk_id, l.id, watr_id);
} }
} }
} }

View File

@ -0,0 +1,178 @@
#include "items.h"
#define ITEM_PICK_RADIUS 25.0f
#define ITEM_ATTRACT_RADIUS 75.0f
#define ITEM_ATTRACT_FORCE 0.63f
void PickItem(ecs_iter_t *it) {
Position *p = ecs_column(it, Position, 2);
Inventory *inv = ecs_column(it, Inventory, 3);
for (int i = 0; i < it->count; i++) {
if (inv[i].pickup_time > game_time()) continue;
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))) {
Position *p2 = ecs_get_mut(it->world, ents[j], Position, NULL);
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) {
for (size_t k = 0; k < ITEMS_INVENTORY_SIZE; k += 1) {
ItemDrop *item = &inv[i].items[k];
uint16_t item_id = item_find(item->kind);
if ((item->quantity == 0 || (item->quantity != 0 && item->kind == drop->kind)) && item->quantity < item_max_quantity(item_id)) {
uint32_t picked_count = zpl_max(0, drop->quantity);
picked_count = zpl_clamp(picked_count, 0, item_max_quantity(item_id) - item->quantity);
item->quantity += picked_count;
drop->quantity -= picked_count;
if (drop->quantity == 0)
item_despawn(ents[j]);
break;
}
}
} else if (range <= ITEM_ATTRACT_RADIUS) {
p2->x = zpl_lerp(p2->x, p[i].x, ITEM_ATTRACT_FORCE*it->delta_time);
p2->y = zpl_lerp(p2->y, p[i].y, ITEM_ATTRACT_FORCE*it->delta_time);
}
}
}
}
}
#define ITEM_DROP_PICKUP_TIME 2.5f
void DropItem(ecs_iter_t *it) {
Input *in = ecs_column(it, Input, 1);
Position *p = ecs_column(it, Position, 2);
Inventory *inv = ecs_column(it, Inventory, 3);
for (int i = 0; i < it->count; i++) {
if (!in[i].drop) continue;
ItemDrop *item = &inv[i].items[in[i].selected_item];
if (item->quantity <= 0)
continue;
bool is_item_nearby = false;
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))) {
Position const* 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) {
if (item->kind == drop->kind) {
uint32_t dropped_count = item->quantity;
if (in[i].sprint) {
dropped_count /= 2;
} else if (in[i].ctrl) {
dropped_count = 1;
}
drop->quantity += dropped_count;
item->quantity -= dropped_count;
is_item_nearby = true;
inv[i].pickup_time = game_time() + ITEM_DROP_PICKUP_TIME;
break;
}
}
}
}
if (!is_item_nearby) {
uint32_t dropped_count = item->quantity;
if (in[i].sprint) {
dropped_count /= 2;
} else if (in[i].ctrl) {
dropped_count = 1;
}
ecs_entity_t te = item_spawn(item->kind, dropped_count);
item->quantity -= dropped_count;
Position *ipos = ecs_get_mut(it->world, te, Position, NULL);
*ipos = p[i];
Velocity *v = ecs_get_mut(it->world, te, Velocity, NULL);
v->x = in[i].mx * 800.0f;
v->y = in[i].my * 800.0f;
inv[i].pickup_time = game_time() + ITEM_DROP_PICKUP_TIME;
}
in[i].drop = false;
}
}
void SwapItems(ecs_iter_t *it) {
Input *in = ecs_column(it, Input, 1);
Inventory *inv = ecs_column(it, Inventory, 2);
for (int i = 0; i < it->count; i++) {
if (!in[i].swap) continue;
ItemDrop *to = &inv[i].items[in[i].swap_to];
ItemDrop *from = &inv[i].items[in[i].swap_from];
uint16_t to_id = item_find(to->kind);
if (to == from) {
// NOTE(zaklaus): do nothing
} else if (to->kind == from->kind && to->quantity > 0) {
uint32_t swapped_count = from->quantity;
if (in[i].sprint) {
swapped_count /= 2;
} else if (in[i].ctrl) {
swapped_count = 1;
}
swapped_count = zpl_clamp(swapped_count, 0, item_max_quantity(to_id) - to->quantity);
to->quantity += swapped_count;
from->quantity -= swapped_count;
if (swapped_count == 0) {
ItemDrop tmp = *to;
*to = *from;
*from = tmp;
}
} else if ((in[i].ctrl || in[i].sprint) && to->quantity == 0 && from->quantity > 0) {
// NOTE(zaklaus): item split
uint32_t split_count = from->quantity / 2;
if (in[i].ctrl) {
split_count = 1;
}
to->quantity = split_count;
from->quantity -= split_count;
to->kind = from->kind;
} else {
ItemDrop tmp = *to;
*to = *from;
*from = tmp;
}
in[i].swap = false;
}
}
void UseItem(ecs_iter_t *it) {
Input *in = ecs_column(it, Input, 1);
Position *p = ecs_column(it, Position, 2);
Inventory *inv = ecs_column(it, Inventory, 3);
for (int i = 0; i < it->count; i++) {
if (!in[i].use) continue;
ItemDrop *item = &inv[i].items[in[i].selected_item];
if (!item || item->quantity <= 0) continue;
item_use(it->world, item, p[i]);
}
}