code: storage system and mouse picking
parent
4164e62a7b
commit
d0d69e7039
|
@ -18,6 +18,7 @@ add_executable(eco2d
|
|||
src/packet.c
|
||||
src/player.c
|
||||
src/vehicle.c
|
||||
src/storage.c
|
||||
src/signal_handling.c
|
||||
src/profiler.c
|
||||
src/debug_ui.c
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
typedef enum {
|
||||
// NOTE(zaklaus): Debug
|
||||
ASSET_EMPTY,
|
||||
ASSET_BLANK,
|
||||
ASSET_BUILDMODE_HIGHLIGHT,
|
||||
|
||||
// NOTE(zaklaus): entities
|
||||
ASSET_PLAYER,
|
||||
ASSET_THING,
|
||||
ASSET_CHEST,
|
||||
|
||||
// NOTE(zaklaus): items
|
||||
ASSET_DEMO_ICEMAKER,
|
||||
|
|
|
@ -12,8 +12,10 @@
|
|||
|
||||
static asset assets[] = {
|
||||
ASSET_TEX(ASSET_EMPTY),
|
||||
ASSET_TEX(ASSET_BLANK),
|
||||
ASSET_TEX(ASSET_BUILDMODE_HIGHLIGHT),
|
||||
ASSET_TEX(ASSET_DEMO_ICEMAKER),
|
||||
ASSET_TEX(ASSET_CHEST),
|
||||
|
||||
// NOTE(zaklaus): blocks
|
||||
ASSET_TEX(ASSET_FENCE),
|
||||
|
|
|
@ -13,6 +13,8 @@ typedef enum {
|
|||
RPKIND_PLACE_ERASE_CHANGES,
|
||||
RPKIND_SPAWN_CIRCLING_DRIVER,
|
||||
RPKIND_SPAWN_ICEMAKER_ITEM,
|
||||
RPKIND_SPAWN_CHEST,
|
||||
RPKIND_SPAWN_BELT,
|
||||
} replay_kind;
|
||||
|
||||
typedef struct {
|
||||
|
@ -174,6 +176,8 @@ void ActPlaceIceRink(void);
|
|||
void ActSpawnCirclingDriver(void);
|
||||
void ActEraseWorldChanges(void);
|
||||
void ActSpawnIcemaker(void);
|
||||
void ActSpawnChest(void);
|
||||
void ActSpawnBelt(void);
|
||||
|
||||
void debug_replay_update(void) {
|
||||
if (!is_playing) return;
|
||||
|
@ -224,6 +228,12 @@ void debug_replay_update(void) {
|
|||
case RPKIND_SPAWN_ICEMAKER_ITEM:{
|
||||
ActSpawnIcemaker();
|
||||
}break;
|
||||
case RPKIND_SPAWN_CHEST:{
|
||||
ActSpawnChest();
|
||||
}break;
|
||||
case RPKIND_SPAWN_BELT:{
|
||||
ActSpawnBelt();
|
||||
}break;
|
||||
default: {
|
||||
ZPL_PANIC("unreachable");
|
||||
}break;
|
||||
|
|
|
@ -133,6 +133,8 @@ static debug_item items[] = {
|
|||
{ .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 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,
|
||||
.name = "demo npcs",
|
||||
|
|
|
@ -32,6 +32,30 @@ ActSpawnIcemaker(void) {
|
|||
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
|
||||
ActSpawnCirclingDriver(void) {
|
||||
ecs_entity_t plr = camera_get().ent_id;
|
||||
|
|
|
@ -10,10 +10,10 @@
|
|||
|
||||
uint64_t entity_spawn(uint16_t class_id) {
|
||||
ecs_entity_t e = ecs_new(world_ecs(), 0);
|
||||
|
||||
|
||||
ecs_set(world_ecs(), e, Classify, { .id = class_id });
|
||||
entity_wake(e);
|
||||
|
||||
|
||||
if (class_id != EKIND_SERVER) {
|
||||
ecs_set(world_ecs(), e, Velocity, {0});
|
||||
Position *pos = ecs_get_mut(world_ecs(), e, Position);
|
||||
|
@ -24,12 +24,12 @@ uint64_t entity_spawn(uint16_t class_id) {
|
|||
pos->x=350.0f;
|
||||
pos->y=88.0f;
|
||||
#endif
|
||||
|
||||
|
||||
librg_entity_track(world_tracker(), e);
|
||||
librg_entity_chunk_set(world_tracker(), e, librg_chunk_from_realpos(world_tracker(), pos->x, pos->y, 0));
|
||||
librg_entity_owner_set(world_tracker(), e, (int64_t)e);
|
||||
}
|
||||
|
||||
|
||||
return (uint64_t)e;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ void entity_set_position(uint64_t ent_id, float x, float y) {
|
|||
Position *p = ecs_get_mut(world_ecs(), ent_id, Position);
|
||||
p->x = x;
|
||||
p->y = y;
|
||||
|
||||
|
||||
entity_wake(ent_id);
|
||||
}
|
||||
|
||||
|
@ -67,12 +67,12 @@ void entity_update_action_timers() {
|
|||
ecs_streaminfo = ecs_query_new(world_ecs(), "components.StreamInfo");
|
||||
last_update_time = zpl_time_rel();
|
||||
}
|
||||
|
||||
|
||||
ecs_iter_t it = ecs_query_iter(world_ecs(), ecs_streaminfo);
|
||||
|
||||
|
||||
while (ecs_query_next(&it)) {
|
||||
StreamInfo *si = ecs_field(&it, StreamInfo, 1);
|
||||
|
||||
|
||||
for (size_t i = 0; i < it.count; i++) {
|
||||
if (si[i].last_update < zpl_time_rel()) {
|
||||
si[i].last_update = zpl_time_rel() + si[i].tick_delay;
|
||||
|
@ -80,7 +80,7 @@ void entity_update_action_timers() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
last_update_time = zpl_time_rel();
|
||||
}
|
||||
|
||||
|
|
|
@ -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_update_action_timers();
|
||||
bool entity_can_stream(uint64_t ent_id);
|
||||
|
||||
|
|
|
@ -36,6 +36,14 @@ pkt_desc pkt_entity_view_desc[] = {
|
|||
{ PKT_UINT(entity_view, selected_item) },
|
||||
{ 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 },
|
||||
};
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ typedef enum {
|
|||
EKIND_SERVER = 0,
|
||||
EKIND_PLAYER,
|
||||
EKIND_ITEM,
|
||||
EKIND_DEVICE,
|
||||
EKIND_VEHICLE,
|
||||
EKIND_DEMO_NPC,
|
||||
EKIND_MONSTER,
|
||||
|
@ -41,10 +42,10 @@ typedef struct entity_view {
|
|||
float vy;
|
||||
float tx;
|
||||
float ty;
|
||||
|
||||
|
||||
float hp;
|
||||
float max_hp;
|
||||
|
||||
|
||||
// TODO(zaklaus): Find a way to stream dynamic arrays
|
||||
uint8_t blocks_used;
|
||||
block_id blocks[256];
|
||||
|
@ -52,24 +53,33 @@ typedef struct entity_view {
|
|||
uint32_t color;
|
||||
uint8_t is_dirty;
|
||||
int64_t tex;
|
||||
|
||||
|
||||
// NOTE(zaklaus): vehicle
|
||||
float heading, theading;
|
||||
bool inside_vehicle;
|
||||
|
||||
|
||||
// NOTE(zaklaus): items, ...
|
||||
asset_id asset;
|
||||
uint32_t quantity;
|
||||
|
||||
|
||||
// NOTE(zaklaus): inventory
|
||||
uint8_t has_items;
|
||||
ItemDrop items[ITEMS_INVENTORY_SIZE];
|
||||
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
|
||||
uint8_t layer_id;
|
||||
uint64_t last_update;
|
||||
|
||||
|
||||
// NOTE(zaklaus): fade in-out effect
|
||||
entity_transition_effect tran_effect;
|
||||
float tran_time;
|
||||
|
|
|
@ -30,7 +30,7 @@ static WORLD_PKT_READER(pkt_reader) {
|
|||
pkt_header header = {0};
|
||||
uint32_t ok = pkt_header_decode(&header, data, datalen);
|
||||
header.udata = udata;
|
||||
|
||||
|
||||
if (ok && header.ok) {
|
||||
return pkt_handlers[header.id].handler(&header) >= 0;
|
||||
} else {
|
||||
|
@ -65,7 +65,7 @@ static WORLD_PKT_WRITER(mp_cli_pkt_writer) {
|
|||
|
||||
void world_viewers_init(uint32_t num_viewers) {
|
||||
zpl_buffer_init(world_viewers, zpl_heap(), num_viewers);
|
||||
|
||||
|
||||
for (uint32_t i = 0; i < num_viewers; i++) {
|
||||
zpl_buffer_append(world_viewers, world_view_create(i));
|
||||
}
|
||||
|
@ -125,31 +125,31 @@ float game_time() {
|
|||
void game_init(const char *ip, uint16_t port, game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled) {
|
||||
game_mode = play_mode;
|
||||
game_should_close = false;
|
||||
|
||||
|
||||
#ifndef _DEBUG
|
||||
const char *host_ip = "lab.zakto.pw";
|
||||
#else
|
||||
const char *host_ip = "127.0.0.1";
|
||||
#endif
|
||||
|
||||
|
||||
uint16_t host_port = (port > 0) ? port : 27000;
|
||||
|
||||
|
||||
if (ip != NULL) {
|
||||
host_ip = ip;
|
||||
}
|
||||
|
||||
|
||||
if (game_mode != GAMEKIND_HEADLESS) {
|
||||
platform_init();
|
||||
|
||||
|
||||
world_viewers_init(num_viewers);
|
||||
active_viewer = &world_viewers[0];
|
||||
camera_reset();
|
||||
}
|
||||
|
||||
|
||||
if (game_mode != GAMEKIND_SINGLE) {
|
||||
network_init();
|
||||
}
|
||||
|
||||
|
||||
if (game_mode == GAMEKIND_CLIENT) {
|
||||
world_setup_pkt_handlers(pkt_reader, mp_cli_pkt_writer);
|
||||
network_client_connect(host_ip, host_port);
|
||||
|
@ -158,13 +158,13 @@ void game_init(const char *ip, uint16_t port, game_kind play_mode, uint32_t num_
|
|||
world_setup_pkt_handlers(pkt_reader, game_mode == GAMEKIND_SINGLE ? sp_pkt_writer : mp_pkt_writer);
|
||||
world_init(seed, chunk_size, chunk_amount);
|
||||
if (is_dash_enabled) flecs_dash_init();
|
||||
|
||||
|
||||
if (game_mode == GAMEKIND_HEADLESS) {
|
||||
network_server_start(0, 27000);
|
||||
//ecs_set_target_fps(world_ecs(), 60);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (game_mode == GAMEKIND_SINGLE) {
|
||||
for (uint32_t i = 0; i < num_viewers; i++) {
|
||||
pkt_00_init_send(i);
|
||||
|
@ -177,24 +177,24 @@ int8_t game_is_networked() {
|
|||
}
|
||||
|
||||
void game_shutdown() {
|
||||
|
||||
|
||||
if (game_mode == GAMEKIND_CLIENT) {
|
||||
network_client_disconnect();
|
||||
} else {
|
||||
world_destroy();
|
||||
|
||||
|
||||
if (game_mode == GAMEKIND_HEADLESS) {
|
||||
network_server_stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (game_mode != GAMEKIND_SINGLE) {
|
||||
network_destroy();
|
||||
}
|
||||
|
||||
|
||||
if (game_mode != GAMEKIND_HEADLESS) {
|
||||
world_viewers_destroy();
|
||||
|
||||
|
||||
// TODO(zaklaus): crashes on exit
|
||||
//platform_shutdown();
|
||||
}
|
||||
|
@ -225,10 +225,10 @@ void game_update() {
|
|||
}
|
||||
else {
|
||||
world_update();
|
||||
|
||||
|
||||
if (game_mode == GAMEKIND_HEADLESS) {
|
||||
network_server_tick();
|
||||
|
||||
|
||||
static uint64_t ms_report = 2500;
|
||||
if (ms_report < zpl_time_rel_ms()) {
|
||||
ms_report = zpl_time_rel_ms() + 5000;
|
||||
|
@ -236,7 +236,7 @@ void game_update() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
last_update = zpl_time_rel();
|
||||
}
|
||||
|
||||
|
@ -250,6 +250,14 @@ void game_action_send_keystate(game_keystate_data *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() {
|
||||
game_should_close = true;
|
||||
if (game_mode != GAMEKIND_HEADLESS) {
|
||||
|
|
|
@ -35,3 +35,4 @@ entity_view *game_world_view_active_get_entity(uint64_t ent_id);
|
|||
|
||||
//~ NOTE(zaklaus): viewer -> host actions
|
||||
void game_action_send_keystate(game_keystate_data *data);
|
||||
void game_action_send_blockpos(float mx, float my);
|
||||
|
|
|
@ -45,6 +45,7 @@ Texture2D texgen_build_anim(asset_id id, int64_t counter) {
|
|||
|
||||
Texture2D texgen_build_sprite(asset_id id) {
|
||||
switch (id) {
|
||||
case ASSET_BLANK: return GenColorEco(WHITE); break;
|
||||
case ASSET_BUILDMODE_HIGHLIGHT: return GenColorEco(WHITE); break;
|
||||
|
||||
// NOTE(zaklaus): items
|
||||
|
|
|
@ -19,18 +19,13 @@ void buildmode_draw(void) {
|
|||
if (inv_is_inside) return;
|
||||
camera cam = camera_get();
|
||||
camera old_cam = cam;
|
||||
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;
|
||||
float mx = 0, my = 0;
|
||||
platform_get_block_realpos(&mx, &my);
|
||||
cam.x = (double)mx;
|
||||
cam.y = (double)my;
|
||||
|
||||
// NOTE(zaklaus): Check distance
|
||||
double dx = old_cam.x - cam.x;
|
||||
|
|
|
@ -1,19 +1,130 @@
|
|||
static uint8_t inv_selected_item = 0;
|
||||
static bool inv_drop_item = false;
|
||||
typedef struct {
|
||||
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;
|
||||
|
||||
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_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() {
|
||||
inv_drop_item = false;
|
||||
inv_swap = false;
|
||||
inv_is_storage_action = false;
|
||||
inv_is_inside = false;
|
||||
inv_swap_storage = false;
|
||||
inventory_reset_states(&player_inv);
|
||||
inventory_reset_states(&storage_inv);
|
||||
|
||||
camera cam = camera_get();
|
||||
entity_view *e = game_world_view_active_get_entity(cam.ent_id);
|
||||
|
@ -27,67 +138,6 @@ void inventory_draw() {
|
|||
return;
|
||||
}
|
||||
|
||||
float sx = screenWidth/2.0f + 128;
|
||||
float sy = screenHeight/2.0f - 96;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
inventory_draw_panel(e, true, screenWidth/2.0f + 128, screenHeight/2.0f - 96);
|
||||
inventory_draw_panel(e, false, screenWidth/2.0f - 384, screenHeight/2.0f - 128);
|
||||
}
|
||||
|
|
|
@ -26,14 +26,14 @@ static inline asset_id item_fix_kind(asset_id id) {
|
|||
|
||||
uint64_t item_spawn(asset_id kind, uint32_t qty) {
|
||||
ecs_entity_t e = entity_spawn(EKIND_ITEM);
|
||||
|
||||
|
||||
ItemDrop *d = ecs_get_mut(world_ecs(), e, ItemDrop);
|
||||
*d = (ItemDrop){
|
||||
.kind = item_fix_kind(kind),
|
||||
.quantity = qty,
|
||||
.merger_time = 0,
|
||||
};
|
||||
|
||||
|
||||
return (uint64_t)e;
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,7 @@ void item_use(ecs_world_t *ecs, ItemDrop *it, Position p, uint64_t udata) {
|
|||
asset_id item_asset = blocks_get_asset(l.bid);
|
||||
item_id item_asset_id = item_find(item_asset);
|
||||
if (item_asset_id == ASSET_INVALID) return;
|
||||
|
||||
|
||||
// NOTE(zaklaus): If we replace the same item, refund 1 qty and let it replace it
|
||||
if (item_asset_id == it_id) {
|
||||
it->quantity++;
|
||||
|
@ -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));
|
||||
it->quantity--;
|
||||
}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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,10 @@ typedef struct {
|
|||
struct {
|
||||
asset_id id;
|
||||
} proxy;
|
||||
|
||||
struct {
|
||||
uint64_t (*spawn_proc)();
|
||||
} place_item;
|
||||
};
|
||||
} item_desc;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "items.h"
|
||||
#include "entity_view.h"
|
||||
|
||||
#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_DIR(asset, qty) ITEM_BLOCK_DIR(asset, qty, asset)
|
||||
|
||||
// NOTE(zaklaus): access to spawners
|
||||
#include "storage.h"
|
||||
|
||||
static item_desc items[] = {
|
||||
{
|
||||
.kind = 0,
|
||||
|
@ -55,4 +69,6 @@ static item_desc items[] = {
|
|||
ITEM_PROXY(ASSET_BELT_RIGHT, ASSET_BELT),
|
||||
ITEM_PROXY(ASSET_BELT_UP, ASSET_BELT),
|
||||
ITEM_PROXY(ASSET_BELT_DOWN, ASSET_BELT),
|
||||
|
||||
ITEM_ENT(ASSET_CHEST, 32, storage_spawn),
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include "compress.h"
|
||||
#include "cwpack/cwpack.h"
|
||||
|
||||
// NOTE(zaklaus): packets
|
||||
//NOTE(zaklaus): packets
|
||||
|
||||
#include "packets/pkt_00_init.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_LIBRG_UPDATE, .handler = pkt_send_librg_update_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},
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ typedef enum {
|
|||
MSG_ID_01_WELCOME,
|
||||
MSG_ID_LIBRG_UPDATE,
|
||||
MSG_ID_SEND_KEYSTATE,
|
||||
MSG_ID_SEND_BLOCKPOS,
|
||||
MSG_ID_SWITCH_VIEWER,
|
||||
MSG_ID_FORCE_UINT16 = UINT16_MAX,
|
||||
} pkt_messages;
|
||||
|
|
|
@ -16,9 +16,13 @@ pkt_desc pkt_send_keystate_desc[] = {
|
|||
{ PKT_UINT(pkt_send_keystate, use) },
|
||||
{ PKT_UINT(pkt_send_keystate, sprint) },
|
||||
{ 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, storage_selected_item) },
|
||||
{ PKT_UINT(pkt_send_keystate, drop) },
|
||||
{ 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_to) },
|
||||
{ PKT_UINT(pkt_send_keystate, placement_num) },
|
||||
|
@ -26,11 +30,23 @@ pkt_desc pkt_send_keystate_desc[] = {
|
|||
{ 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,
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
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)));
|
||||
|
@ -48,11 +64,15 @@ int32_t pkt_send_keystate_handler(pkt_header *header) {
|
|||
i->use |= table.use;
|
||||
i->sprint = table.sprint;
|
||||
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->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);
|
||||
i->swap_storage |= table.swap_storage;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,15 @@ typedef struct {
|
|||
uint8_t use;
|
||||
uint8_t sprint;
|
||||
uint8_t ctrl;
|
||||
uint8_t pick;
|
||||
|
||||
// NOTE(zaklaus): inventory
|
||||
uint8_t storage_action;
|
||||
uint8_t selected_item;
|
||||
uint8_t storage_selected_item;
|
||||
uint8_t drop;
|
||||
uint8_t swap;
|
||||
uint8_t swap_storage;
|
||||
uint8_t swap_from;
|
||||
uint8_t swap_to;
|
||||
|
||||
|
@ -22,11 +28,22 @@ typedef struct {
|
|||
item_placement placements[BUILD_MAX_PLACEMENTS];
|
||||
} pkt_send_keystate;
|
||||
|
||||
typedef struct {
|
||||
float mx;
|
||||
float my;
|
||||
} pkt_send_blockpos;
|
||||
|
||||
typedef pkt_send_keystate game_keystate_data;
|
||||
|
||||
size_t pkt_send_keystate_send(uint16_t view_id,
|
||||
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_blockpos_desc[];
|
||||
|
||||
PKT_HANDLER_PROC(pkt_send_keystate_handler);
|
||||
PKT_HANDLER_PROC(pkt_send_blockpos_handler);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ void platform_shutdown(void);
|
|||
void platform_request_close(void);
|
||||
float platform_frametime(void);
|
||||
uint8_t platform_is_running(void);
|
||||
void platform_get_block_realpos(float *x, float *y);
|
||||
|
||||
float platform_zoom_get(void);
|
||||
|
||||
|
|
|
@ -60,16 +60,46 @@ uint8_t platform_is_running() {
|
|||
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 pkt_send_blockpos last_blockpos_data = {0};
|
||||
|
||||
inline static
|
||||
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
|
||||
if (data.x != last_input_data.x) 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.sprint != last_input_data.sprint) 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.drop != last_input_data.drop) goto send_data;
|
||||
if (data.swap != last_input_data.swap) goto send_data;
|
||||
|
@ -94,7 +124,7 @@ void platform_input() {
|
|||
// NOTE(zaklaus): keystate handling
|
||||
{
|
||||
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_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f;
|
||||
if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f;
|
||||
|
@ -103,7 +133,7 @@ void platform_input() {
|
|||
use = IsKeyPressed(KEY_SPACE);
|
||||
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;
|
||||
drop = IsKeyPressed(KEY_G) || player_inv.drop_item || storage_inv.drop_item;
|
||||
|
||||
// NOTE(zaklaus): NEW! mouse movement
|
||||
Vector2 mouse_pos = GetMousePosition();
|
||||
|
@ -118,6 +148,11 @@ void platform_input() {
|
|||
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 = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
|
@ -126,12 +161,16 @@ void platform_input() {
|
|||
.use = use,
|
||||
.sprint = sprint,
|
||||
.ctrl = ctrl,
|
||||
.pick = pick,
|
||||
|
||||
.drop = drop,
|
||||
.selected_item = inv_selected_item,
|
||||
.swap = inv_swap,
|
||||
.swap_from = inv_swap_from,
|
||||
.swap_to = inv_swap_to,
|
||||
.storage_action = inv_is_storage_action,
|
||||
.selected_item = player_inv.selected_item,
|
||||
.storage_selected_item = storage_inv.selected_item,
|
||||
.swap = inv->swap,
|
||||
.swap_storage = inv_swap_storage,
|
||||
.swap_from = inv->swap_from,
|
||||
.swap_to = inv->swap_to,
|
||||
};
|
||||
|
||||
if (build_submit_placements) {
|
||||
|
@ -169,6 +208,26 @@ void platform_input() {
|
|||
#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() {
|
||||
screenWidth = (uint16_t)GetScreenWidth();
|
||||
screenHeight = (uint16_t)GetScreenHeight();
|
||||
|
@ -184,6 +243,7 @@ void platform_render() {
|
|||
{
|
||||
profile (PROF_RENDER) {
|
||||
renderer_draw();
|
||||
draw_selected_item();
|
||||
}
|
||||
renderer_debug_draw();
|
||||
{
|
||||
|
|
|
@ -113,6 +113,11 @@ void DEBUG_draw_entities_low(uint64_t key, entity_view * data) {
|
|||
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));
|
||||
}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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "system.h"
|
||||
|
||||
uint64_t storage_spawn(void);
|
||||
void storage_despawn(uint64_t id);
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
@ -13,4 +14,4 @@
|
|||
#define defer(s,e) for ( \
|
||||
uint32_t defer_var = (s, 0); \
|
||||
!defer_var; \
|
||||
(defer_var += 1), e)
|
||||
(defer_var += 1), e)
|
|
@ -71,8 +71,24 @@ entity_view world_build_entity_view(int64_t e) {
|
|||
}
|
||||
|
||||
const Input *in = ecs_get(world_ecs(), e, Input);
|
||||
if (in)
|
||||
if (in){
|
||||
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;
|
||||
|
|
|
@ -252,6 +252,14 @@ int32_t worldgen_test(world_data *wld) {
|
|||
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
|
||||
|
||||
return WORLD_ERROR_NONE;
|
||||
|
|
|
@ -13,12 +13,13 @@ ECS_COMPONENT_DECLARE(Vehicle);
|
|||
ECS_COMPONENT_DECLARE(IsInVehicle);
|
||||
ECS_COMPONENT_DECLARE(ItemDrop);
|
||||
ECS_COMPONENT_DECLARE(Inventory);
|
||||
ECS_COMPONENT_DECLARE(ItemContainer);
|
||||
ECS_COMPONENT_DECLARE(DemoNPC);
|
||||
ECS_COMPONENT_DECLARE(StreamInfo);
|
||||
|
||||
void ComponentsImport(ecs_world_t *ecs) {
|
||||
ECS_MODULE(ecs, Components);
|
||||
|
||||
|
||||
ECS_COMPONENT_DEFINE(ecs, Vector2D);
|
||||
ECS_COMPONENT_DEFINE(ecs, Position);
|
||||
ECS_COMPONENT_DEFINE(ecs, Velocity);
|
||||
|
@ -32,6 +33,7 @@ void ComponentsImport(ecs_world_t *ecs) {
|
|||
ECS_COMPONENT_DEFINE(ecs, IsInVehicle);
|
||||
ECS_COMPONENT_DEFINE(ecs, ItemDrop);
|
||||
ECS_COMPONENT_DEFINE(ecs, Inventory);
|
||||
ECS_COMPONENT_DEFINE(ecs, ItemContainer);
|
||||
ECS_COMPONENT_DEFINE(ecs, DemoNPC);
|
||||
ECS_COMPONENT_DEFINE(ecs, StreamInfo);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#endif
|
||||
|
||||
#define ITEMS_INVENTORY_SIZE 9
|
||||
#define ITEMS_CONTAINER_SIZE 16
|
||||
|
||||
typedef struct {
|
||||
float x;
|
||||
|
@ -32,15 +33,24 @@ typedef struct {
|
|||
float y;
|
||||
float mx;
|
||||
float my;
|
||||
float bx;
|
||||
float by;
|
||||
uint8_t use;
|
||||
uint8_t sprint;
|
||||
uint8_t ctrl;
|
||||
uint8_t pick;
|
||||
uint8_t is_blocked;
|
||||
ecs_entity_t pick_ent;
|
||||
ecs_entity_t sel_ent;
|
||||
|
||||
// NOTE(zaklaus): inventory
|
||||
ecs_entity_t storage_ent;
|
||||
uint8_t storage_action;
|
||||
uint8_t selected_item;
|
||||
uint8_t storage_selected_item;
|
||||
uint8_t drop;
|
||||
uint8_t swap;
|
||||
uint8_t swap_storage;
|
||||
uint8_t swap_from;
|
||||
uint8_t swap_to;
|
||||
|
||||
|
@ -92,10 +102,14 @@ typedef struct {
|
|||
} ItemDrop;
|
||||
|
||||
typedef struct {
|
||||
ItemDrop items[ITEMS_INVENTORY_SIZE];
|
||||
ItemDrop items[ITEMS_CONTAINER_SIZE];
|
||||
float pickup_time;
|
||||
} Inventory;
|
||||
|
||||
typedef struct {
|
||||
ItemDrop items[ITEMS_CONTAINER_SIZE];
|
||||
} ItemContainer;
|
||||
|
||||
typedef struct {
|
||||
double last_update;
|
||||
double tick_delay;
|
||||
|
@ -116,6 +130,7 @@ extern ECS_COMPONENT_DECLARE(Vehicle);
|
|||
extern ECS_COMPONENT_DECLARE(IsInVehicle);
|
||||
extern ECS_COMPONENT_DECLARE(ItemDrop);
|
||||
extern ECS_COMPONENT_DECLARE(Inventory);
|
||||
extern ECS_COMPONENT_DECLARE(ItemContainer);
|
||||
extern ECS_COMPONENT_DECLARE(DemoNPC);
|
||||
extern ECS_COMPONENT_DECLARE(StreamInfo);
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ void IntegratePositions(ecs_iter_t *it) {
|
|||
profile(PROF_INTEGRATE_POS) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Velocity *v = ecs_field(it, Velocity, 2);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
// NOTE(zaklaus): world bounds
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ void IntegratePositions(ecs_iter_t *it) {
|
|||
p[i].x = zpl_clamp(p[i].x, 0, w-1);
|
||||
p[i].y = zpl_clamp(p[i].y, 0, w-1);
|
||||
}
|
||||
|
||||
|
||||
#if PHY_BLOCK_COLLISION==1
|
||||
// NOTE(zaklaus): X axis
|
||||
{
|
||||
|
@ -44,7 +44,7 @@ void IntegratePositions(ecs_iter_t *it) {
|
|||
v[i].x = physics_correction(lookup.ox, v[i].x, bounce);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): Y axis
|
||||
{
|
||||
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y+PHY_LOOKAHEAD(v[i].y));
|
||||
|
@ -55,10 +55,10 @@ void IntegratePositions(ecs_iter_t *it) {
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
p[i].x += v[i].x * safe_dt(it);
|
||||
p[i].y += v[i].y * safe_dt(it);
|
||||
|
||||
|
||||
{
|
||||
debug_v2 a = {p[i].x, p[i].y};
|
||||
debug_v2 b = {p[i].x+v[i].x, p[i].y+v[i].y};
|
||||
|
@ -70,10 +70,10 @@ void IntegratePositions(ecs_iter_t *it) {
|
|||
|
||||
void UpdateTrackerPos(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++){
|
||||
librg_entity_chunk_set(world_tracker(), it->entities[i], librg_chunk_from_realpos(world_tracker(), p[i].x, p[i].y, 0));
|
||||
|
||||
|
||||
{
|
||||
debug_v2 a = {p[i].x-2.5f, p[i].y-2.5f};
|
||||
debug_v2 b = {p[i].x+2.5f, p[i].y+2.5f};
|
||||
|
@ -88,7 +88,7 @@ void UpdateTrackerPos(ecs_iter_t *it) {
|
|||
void HurtOnHazardBlock(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Health *h = ecs_field(it, Health, 2);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y);
|
||||
if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) {
|
||||
|
@ -107,7 +107,7 @@ void HurtOnHazardBlock(ecs_iter_t *it) {
|
|||
|
||||
void RegenerateHP(ecs_iter_t *it) {
|
||||
Health *h = ecs_field(it, Health, 1);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
if (h[i].pain_time < 0.0f) {
|
||||
if (h[i].heal_time < 0.0f && h[i].hp < h[i].max_hp) {
|
||||
|
@ -126,11 +126,12 @@ void RegenerateHP(ecs_iter_t *it) {
|
|||
|
||||
void ResetActivators(ecs_iter_t *it) {
|
||||
Input *in = ecs_field(it, Input, 1);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
in[i].use = false;
|
||||
in[i].swap = false;
|
||||
in[i].drop = false;
|
||||
in[i].pick = false;
|
||||
in[i].num_placements = 0;
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +139,7 @@ void ResetActivators(ecs_iter_t *it) {
|
|||
void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Velocity *v = ecs_field(it, Velocity, 2);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y);
|
||||
float drag = zpl_clamp(blocks_get_drag(lookup.bid), 0.0f, 1.0f);
|
||||
|
@ -147,6 +148,43 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
|
|||
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].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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,33 +199,36 @@ void DisableWorldEdit(ecs_iter_t *it) {
|
|||
|
||||
void SystemsImport(ecs_world_t *ecs) {
|
||||
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, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.DemoNPC);
|
||||
|
||||
|
||||
ECS_SYSTEM(ecs, ApplyWorldDragOnVelocity, EcsOnUpdate, components.Position, components.Velocity);
|
||||
ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health);
|
||||
ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health);
|
||||
ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity);
|
||||
|
||||
|
||||
ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, components.Position, components.Velocity);
|
||||
|
||||
|
||||
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, PlayerClosestInteractable, EcsPostUpdate, components.Input);
|
||||
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, MergeItems, EcsPostUpdate, components.Position, components.ItemDrop);
|
||||
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, UpdateTrackerPos, EcsPostUpdate, components.Position, components.Velocity);
|
||||
|
||||
|
||||
ECS_SYSTEM(ecs, ClearVehicle, EcsUnSet, components.Vehicle);
|
||||
|
||||
|
||||
ECS_SYSTEM(ecs, DisableWorldEdit, EcsPostUpdate);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,20 +5,22 @@
|
|||
#define ITEM_ATTRACT_RADIUS 75.0f
|
||||
#define ITEM_ATTRACT_FORCE 0.63f
|
||||
|
||||
#define ITEM_CONTAINER_REACH_RADIUS 105.0f
|
||||
|
||||
void PickItem(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 2);
|
||||
Inventory *inv = ecs_field(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);
|
||||
|
||||
|
||||
float dx = p2->x - p[i].x;
|
||||
float dy = p2->y - p[i].y;
|
||||
float range = zpl_sqrt(dx*dx + dy*dy);
|
||||
|
@ -34,7 +36,7 @@ void PickItem(ecs_iter_t *it) {
|
|||
drop->quantity -= picked_count;
|
||||
item->kind = drop->kind;
|
||||
entity_wake(ents[j]);
|
||||
|
||||
|
||||
if (drop->quantity == 0)
|
||||
item_despawn(ents[j]);
|
||||
break;
|
||||
|
@ -57,45 +59,60 @@ void DropItem(ecs_iter_t *it) {
|
|||
Input *in = ecs_field(it, Input, 1);
|
||||
Position *p = ecs_field(it, Position, 2);
|
||||
Inventory *inv = ecs_field(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];
|
||||
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
|
||||
uint32_t dropped_count = item->quantity;
|
||||
if (in[i].sprint) {
|
||||
dropped_count /= 2;
|
||||
} else if (in[i].ctrl) {
|
||||
dropped_count = dropped_count > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
if (dropped_count == 0)
|
||||
continue;
|
||||
|
||||
|
||||
ecs_entity_t te = item_spawn(item->kind, dropped_count);
|
||||
item->quantity -= dropped_count;
|
||||
|
||||
|
||||
ItemDrop *d = ecs_get_mut(world_ecs(), te, ItemDrop);
|
||||
*d = (ItemDrop){
|
||||
.kind = item->kind,
|
||||
.quantity = dropped_count,
|
||||
.merger_time = game_time() + ITEM_DROP_MERGER_TIME,
|
||||
};
|
||||
|
||||
|
||||
Position *ipos = ecs_get_mut(it->world, te, Position);
|
||||
*ipos = p[i];
|
||||
|
||||
|
||||
Velocity *v = ecs_get_mut(it->world, te, Velocity);
|
||||
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;
|
||||
|
||||
|
||||
if (item->quantity == 0) {
|
||||
item->kind = 0;
|
||||
}
|
||||
|
@ -105,24 +122,24 @@ void DropItem(ecs_iter_t *it) {
|
|||
void MergeItems(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
ItemDrop *id = ecs_field(it, ItemDrop, 2);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i += 1) {
|
||||
ItemDrop *item = &id[i];
|
||||
|
||||
|
||||
if (item->merger_time < game_time())
|
||||
continue;
|
||||
|
||||
|
||||
size_t ents_count;
|
||||
int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 1);
|
||||
|
||||
|
||||
for (size_t j = 0; j < ents_count; j++) {
|
||||
ItemDrop *drop = 0;
|
||||
if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) {
|
||||
if (drop->kind != item->kind || (ecs_entity_t)ents[j] == it->entities[i] || drop->quantity == 0 || item->quantity == 0)
|
||||
continue;
|
||||
|
||||
|
||||
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);
|
||||
|
@ -139,14 +156,56 @@ void MergeItems(ecs_iter_t *it) {
|
|||
void SwapItems(ecs_iter_t *it) {
|
||||
Input *in = ecs_field(it, Input, 1);
|
||||
Inventory *inv = ecs_field(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];
|
||||
|
||||
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 *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);
|
||||
|
||||
|
||||
if (to == from) {
|
||||
// NOTE(zaklaus): do nothing
|
||||
} else if (to->kind == from->kind && to->quantity > 0) {
|
||||
|
@ -159,7 +218,7 @@ void SwapItems(ecs_iter_t *it) {
|
|||
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;
|
||||
|
@ -179,7 +238,7 @@ void SwapItems(ecs_iter_t *it) {
|
|||
*to = *from;
|
||||
*from = tmp;
|
||||
}
|
||||
|
||||
|
||||
in[i].swap = false;
|
||||
}
|
||||
}
|
||||
|
@ -188,15 +247,19 @@ void UseItem(ecs_iter_t *it) {
|
|||
Input *in = ecs_field(it, Input, 1);
|
||||
Position *p = ecs_field(it, Position, 2);
|
||||
Inventory *inv = ecs_field(it, Inventory, 3);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
if (!in[i].use && !in[i].num_placements) continue;
|
||||
|
||||
|
||||
if (in[i].storage_action){
|
||||
continue;
|
||||
}
|
||||
|
||||
ItemDrop *item = &inv[i].items[in[i].selected_item];
|
||||
if (!item || item->quantity <= 0) continue;
|
||||
uint16_t item_id = item_find(item->kind);
|
||||
item_usage usage = item_get_usage(item_id);
|
||||
|
||||
|
||||
if (in[i].use && usage > UKIND_END_PLACE)
|
||||
item_use(it->world, item, p[i], 0);
|
||||
else if (in[i].num_placements > 0 && usage < UKIND_END_PLACE) {
|
||||
|
@ -216,15 +279,69 @@ void UseItem(ecs_iter_t *it) {
|
|||
// NOTE(zaklaus): ensure we pick the first variant
|
||||
ofs = 1;
|
||||
}
|
||||
|
||||
|
||||
for (size_t j = 0; j < in[i].num_placements; j++) {
|
||||
Position pos = {.x = in[i].placements_x[j], .y = in[i].placements_y[j]};
|
||||
item_use(it->world, item, pos, ofs);
|
||||
}
|
||||
|
||||
|
||||
in[i].num_placements = 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue