diff --git a/code/game/src/assets.h b/code/game/src/assets.h index caa311c..2a2e1de 100644 --- a/code/game/src/assets.h +++ b/code/game/src/assets.h @@ -1,36 +1,39 @@ -#pragma once -#include "system.h" - -#define ASSET_INVALID 0xFF - -typedef enum { - // NOTE(zaklaus): entities - ASSET_PLAYER, - ASSET_THING, - - // NOTE(zaklaus): items - ASSET_DEMO_ICEMAKER, - - MAX_ASSETS, - FORCE_ASSET_UINT16 = UINT16_MAX -} asset_id; - -typedef enum { - AKIND_TEXTURE, - AKIND_SOUND, - - FORCE_AKIND_UINT8 = UINT8_MAX -} asset_kind; - -int32_t assets_setup(void); -void assets_destroy(void); - -uint16_t assets_find(asset_id id); - -asset_kind assets_get_kind(uint16_t id); -void *assets_get_snd(uint16_t id); -void *assets_get_tex(uint16_t id); - -// NOTE(zaklaus): client only -#define ASSET_SRC_RECT() ((Rectangle){0, 0, 64, 64}) -#define ASSET_DST_RECT(x,y) ((Rectangle){x, y, 64, 64}) +#pragma once +#include "system.h" + +#define ASSET_INVALID 0xFF + +typedef enum { + // NOTE(zaklaus): Debug + ASSET_DEBUG_TILE, + + // NOTE(zaklaus): entities + ASSET_PLAYER, + ASSET_THING, + + // NOTE(zaklaus): items + ASSET_DEMO_ICEMAKER, + + MAX_ASSETS, + FORCE_ASSET_UINT16 = UINT16_MAX +} asset_id; + +typedef enum { + AKIND_TEXTURE, + AKIND_SOUND, + + FORCE_AKIND_UINT8 = UINT8_MAX +} asset_kind; + +int32_t assets_setup(void); +void assets_destroy(void); + +uint16_t assets_find(asset_id id); + +asset_kind assets_get_kind(uint16_t id); +void *assets_get_snd(uint16_t id); +void *assets_get_tex(uint16_t id); + +// NOTE(zaklaus): client only +#define ASSET_SRC_RECT() ((Rectangle){0, 0, 64, 64}) +#define ASSET_DST_RECT(x,y) ((Rectangle){x, y, 64, 64}) diff --git a/code/game/src/assets_list.c b/code/game/src/assets_list.c index 5a272a3..29fe5b6 100644 --- a/code/game/src/assets_list.c +++ b/code/game/src/assets_list.c @@ -1,8 +1,12 @@ -#include "assets.h" - -static asset assets[] = { - { - .id = ASSET_DEMO_ICEMAKER, - .kind = AKIND_TEXTURE, - } -}; +#include "assets.h" + +static asset assets[] = { + { + .id = ASSET_DEBUG_TILE, + .kind = AKIND_TEXTURE, + }, + { + .id = ASSET_DEMO_ICEMAKER, + .kind = AKIND_TEXTURE, + } +}; diff --git a/code/game/src/debug_replay.c b/code/game/src/debug_replay.c index 42590e2..25ed262 100644 --- a/code/game/src/debug_replay.c +++ b/code/game/src/debug_replay.c @@ -197,6 +197,11 @@ void debug_replay_update(void) { i->swap = r->pkt.swap; i->swap_from = r->pkt.swap_from; i->swap_to = r->pkt.swap_to; + i->num_placements = r->pkt.placement_num; + for (uint8_t j = 0; j < i->num_placements; j++) { + i->placements_x[j] = r->pkt.placements[j].x; + i->placements_y[j] = r->pkt.placements[j].y; + } }break; case RPKIND_SPAWN_CAR: { ecs_entity_t e = vehicle_spawn(); diff --git a/code/game/src/gui/build_mode.c b/code/game/src/gui/build_mode.c new file mode 100644 index 0000000..3caf28b --- /dev/null +++ b/code/game/src/gui/build_mode.c @@ -0,0 +1,71 @@ +#include "camera.h" +#include "item_placement.h" + +static bool build_submit_placements = false; +static bool build_is_in_draw_mode = false; +static uint8_t build_num_placements = 0; +static item_placement build_placements[BUILD_MAX_PLACEMENTS] = {0}; + +void buildmode_draw() { + if (inv_is_open) return; + 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 (e->has_items && !e->inside_vehicle && e->items[e->selected_item].quantity > 0) { + if (IsMouseButtonDown(MOUSE_LEFT_BUTTON) && !build_is_in_draw_mode) { + build_is_in_draw_mode = true; + build_num_placements = 0; + + item_placement empty_placement = { .x = 0.0f, .y = 0.0f, .kind = -1 }; + for (size_t i = 0; i < BUILD_MAX_PLACEMENTS; i++) { + zpl_memcopy(&build_placements[i], &empty_placement, zpl_size_of(item_placement)); + } + } + + uint32_t qty = e->items[e->selected_item].quantity; + + if (build_is_in_draw_mode) { + for (size_t i = 0; i < BUILD_MAX_PLACEMENTS; i++) { + item_placement *it = &build_placements[i]; + if (it->kind == -1) { + it->x = (float)cam.x; + it->y = (float)cam.y; + it->kind = 0; + build_num_placements++; + break; + } else if (it->x == (float)cam.x && it->y == (float)cam.y) { + break; + } + } + + build_num_placements = zpl_min(build_num_placements, qty); + + for (size_t i = 0; i < build_num_placements; i++) { + item_placement *it = &build_placements[i]; + renderer_draw_single(it->x, it->y, ASSET_DEBUG_TILE, ColorAlpha(BLUE, 0.4f)); + } + + if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) { + build_is_in_draw_mode = false; + } + + if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) { + build_submit_placements = true; + build_is_in_draw_mode = false; + } + } + + renderer_draw_single(cam.x, cam.y, ASSET_DEBUG_TILE, ColorAlpha(BLUE, 0.4f)); + } +} \ No newline at end of file diff --git a/code/game/src/gui/inventory.c b/code/game/src/gui/inventory.c index c93a423..da7886f 100644 --- a/code/game/src/gui/inventory.c +++ b/code/game/src/gui/inventory.c @@ -24,7 +24,9 @@ void inventory_draw() { inv_is_open = !inv_is_open; } - if (!inv_is_open) return; + if (!inv_is_open) { + return; + } float sx = screenWidth/2.0f + 128; float sy = screenHeight/2.0f - 96; diff --git a/code/game/src/item_placement.h b/code/game/src/item_placement.h new file mode 100644 index 0000000..f2fb961 --- /dev/null +++ b/code/game/src/item_placement.h @@ -0,0 +1,10 @@ +#pragma once + +#define BUILD_MAX_PLACEMENTS 20 + +typedef struct { + float x; + float y; + float rot; + int16_t kind; +} item_placement; diff --git a/code/game/src/items.c b/code/game/src/items.c index e372816..5b659ae 100644 --- a/code/game/src/items.c +++ b/code/game/src/items.c @@ -36,6 +36,7 @@ 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]; + if (it->quantity <= 0) return; switch (item_get_usage(item_id)) { case UKIND_PLACE:{ world_block_lookup l = world_block_from_realpos(p.x, p.y); diff --git a/code/game/src/items.h b/code/game/src/items.h index 2436b4e..c3d0a49 100644 --- a/code/game/src/items.h +++ b/code/game/src/items.h @@ -13,6 +13,8 @@ typedef enum { typedef enum { UKIND_PLACE, + UKIND_PLACE_ITEM, + UKIND_END_PLACE, } item_usage; typedef struct { diff --git a/code/game/src/packets/pkt_send_keystate.c b/code/game/src/packets/pkt_send_keystate.c index 47aa201..25cda91 100644 --- a/code/game/src/packets/pkt_send_keystate.c +++ b/code/game/src/packets/pkt_send_keystate.c @@ -20,6 +20,8 @@ pkt_desc pkt_send_keystate_desc[] = { { PKT_UINT(pkt_send_keystate, swap) }, { PKT_UINT(pkt_send_keystate, swap_from) }, { PKT_UINT(pkt_send_keystate, swap_to) }, + { PKT_UINT(pkt_send_keystate, placement_num) }, + { PKT_ARRAY(pkt_send_keystate, placements) }, { PKT_END }, }; @@ -57,6 +59,11 @@ int32_t pkt_send_keystate_handler(pkt_header *header) { 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->num_placements = zpl_clamp(table.placement_num, 0, BUILD_MAX_PLACEMENTS); + for (uint8_t j = 0; j < i->num_placements; j++) { + i->placements_x[j] = table.placements[j].x; + i->placements_y[j] = table.placements[j].y; + } debug_replay_record_keystate(table); } diff --git a/code/game/src/packets/pkt_send_keystate.h b/code/game/src/packets/pkt_send_keystate.h index 89811dd..1772a63 100644 --- a/code/game/src/packets/pkt_send_keystate.h +++ b/code/game/src/packets/pkt_send_keystate.h @@ -1,6 +1,7 @@ #pragma once #include "system.h" #include "packet_utils.h" +#include "item_placement.h" typedef struct { float x; @@ -15,6 +16,10 @@ typedef struct { uint8_t swap; uint8_t swap_from; uint8_t swap_to; + + // TODO(zaklaus): build mode + uint8_t placement_num; + item_placement placements[BUILD_MAX_PLACEMENTS]; } pkt_send_keystate; typedef pkt_send_keystate game_keystate_data; diff --git a/code/game/src/platform_raylib.c b/code/game/src/platform_raylib.c index d053243..4a1814a 100644 --- a/code/game/src/platform_raylib.c +++ b/code/game/src/platform_raylib.c @@ -23,6 +23,7 @@ static bool request_shutdown; // NOTE(zaklaus): add-ins #include "gui/inventory.c" +#include "gui/build_mode.c" void platform_init() { InitWindow(screenWidth, screenHeight, "eco2d"); @@ -106,6 +107,13 @@ void platform_input() { .swap_to = inv_swap_to, }; + if (build_submit_placements) { + build_submit_placements = false; + + data.placement_num = build_num_placements; + zpl_memcopy(data.placements, build_placements, build_num_placements*zpl_size_of(item_placement)); + } + game_action_send_keystate(&data); } @@ -151,6 +159,7 @@ void platform_render() { { // NOTE(zaklaus): add-ins inventory_draw(); + buildmode_draw(); } display_conn_status(); debug_draw(); diff --git a/code/game/src/renderer_3d.c b/code/game/src/renderer_3d.c index 4948c21..27b6330 100644 --- a/code/game/src/renderer_3d.c +++ b/code/game/src/renderer_3d.c @@ -133,4 +133,15 @@ void renderer_shutdown_3d(void) { void renderer_debug_draw_3d(void) { -} \ No newline at end of file +} + +float renderer_zoom_get_3d(void) { + return 1.0f; +} + +void renderer_draw_single_3d(float x, float y, asset_id id, Color color) { + (void)color; + BeginMode3D(render_camera_3d); + EcoDrawCube((Vector3){x, 15.0f, y}, 16, 16, 16, 0.0f, PINK); + EndMode3D(); +} diff --git a/code/game/src/renderer_bridge.c b/code/game/src/renderer_bridge.c index dfe169c..37d11e0 100644 --- a/code/game/src/renderer_bridge.c +++ b/code/game/src/renderer_bridge.c @@ -6,7 +6,9 @@ #define renderer_init renderer_init_v0 #define renderer_shutdown renderer_shutdown_v0 #define renderer_draw renderer_draw_v0 +#define renderer_draw_single renderer_draw_single_v0 #define renderer_debug_draw renderer_debug_draw_v0 +#define renderer_zoom_get renderer_zoom_get_v0 void renderer_switch(int kind) {} #elif GFX_KIND == 1 // NOTE(zaklaus): renderer_3d @@ -14,7 +16,9 @@ void renderer_switch(int kind) {} #define renderer_init renderer_init_3d #define renderer_shutdown renderer_shutdown_3d #define renderer_draw renderer_draw_3d +#define renderer_draw_single renderer_draw_single_3d #define renderer_debug_draw renderer_debug_draw_3d +#define renderer_zoom_get renderer_zoom_get_3d void renderer_switch(int kind) {} #elif GFX_KIND == 2 #include "renderer_3d.c" @@ -66,6 +70,29 @@ void renderer_debug_draw(void) { } } +float renderer_zoom_get(void) { + switch (gfx_kind) { + case 0:{ + return renderer_zoom_get_v0(); + }break; + case 1:{ + return renderer_zoom_get_3d(); + }break; + } + return 1.0f; +} + +void renderer_draw_single(float x, float y, asset_id id, Color color) { + switch (gfx_kind) { + case 0:{ + renderer_draw_single_v0(x, y, id, color); + }break; + case 1:{ + renderer_draw_single_3d(x, y, id, color); + }break; + } +} + void renderer_bake_chunk(uint64_t key, entity_view * data) { if (data->kind != EKIND_CHUNK) return; world_view *view = game_world_view_get_active(); diff --git a/code/game/src/renderer_v0.c b/code/game/src/renderer_v0.c index 0d34045..8f5f648 100644 --- a/code/game/src/renderer_v0.c +++ b/code/game/src/renderer_v0.c @@ -127,6 +127,10 @@ void renderer_draw_v0(void) { EndMode2D(); } +float renderer_zoom_get_v0(void) { + return render_camera.zoom; +} + void renderer_init_v0(void) { render_camera.target = (Vector2){0.0f,0.0f}; render_camera.offset = (Vector2){screenWidth >> 1, screenHeight >> 1}; @@ -191,4 +195,15 @@ void renderer_debug_draw_v0(void) { } EndMode2D(); -} \ No newline at end of file +} + +void renderer_draw_single_v0(float x, float y, asset_id id, Color color) { + BeginMode2D(render_camera); + + x -= 32.0f; + y -= 32.0f; + + DrawTexturePro(GetSpriteTexture2D(assets_find(id)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, color); + + EndMode2D(); +} diff --git a/code/modules/modules/components.h b/code/modules/modules/components.h index 1a6601c..9fe981a 100644 --- a/code/modules/modules/components.h +++ b/code/modules/modules/components.h @@ -52,6 +52,11 @@ ECS_STRUCT(Input, { uint8_t swap; uint8_t swap_from; uint8_t swap_to; + + // NOTE(zaklaus): build mode + uint8_t num_placements; + float placements_x[20]; + float placements_y[20]; }); ECS_STRUCT(ClientInfo, { diff --git a/code/modules/source/system_items.c b/code/modules/source/system_items.c index dce0a01..5b87345 100644 --- a/code/modules/source/system_items.c +++ b/code/modules/source/system_items.c @@ -182,10 +182,20 @@ void UseItem(ecs_iter_t *it) { Inventory *inv = ecs_column(it, Inventory, 3); for (int i = 0; i < it->count; i++) { - if (!in[i].use) continue; + if (!in[i].use && !in[i].num_placements) continue; ItemDrop *item = &inv[i].items[in[i].selected_item]; if (!item || item->quantity <= 0) continue; - item_use(it->world, item, p[i]); + 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]); + else if (in[i].num_placements > 0 && usage < UKIND_END_PLACE) { + 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); + } + } } } \ No newline at end of file diff --git a/screenshot000.png b/screenshot000.png new file mode 100644 index 0000000..157d614 Binary files /dev/null and b/screenshot000.png differ