diff --git a/code/foundation/src/debug/debug_ui.c b/code/foundation/src/debug/debug_ui.c index 96ad7f6..4d57259 100644 --- a/code/foundation/src/debug/debug_ui.c +++ b/code/foundation/src/debug/debug_ui.c @@ -142,6 +142,7 @@ static debug_item items[] = { { .kind = DITEM_BUTTON, .name = "spawn belt", .on_click = ActSpawnBelt }, { .kind = DITEM_BUTTON, .name = "spawn furnace", .on_click = ActSpawnFurnace }, { .kind = DITEM_BUTTON, .name = "spawn demo blueprint", .on_click = ActSpawnDemoHouseItem }, + { .kind = DITEM_BUTTON, .name = "spawn random durability icemaker", .on_click = ActSpawnDurabilityTest }, { .kind = DITEM_LIST, .name = "demo npcs", diff --git a/code/foundation/src/debug/debug_ui_actions.c b/code/foundation/src/debug/debug_ui_actions.c index aad8e9e..7529882 100644 --- a/code/foundation/src/debug/debug_ui_actions.c +++ b/code/foundation/src/debug/debug_ui_actions.c @@ -12,12 +12,12 @@ void ActSpawnCar(void) { ecs_entity_t e = vehicle_spawn(EVEH_CAR); 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; entity_set_position(e, dest->x, dest->y); - + debug_replay_special_action(RPKIND_SPAWN_CAR); } @@ -25,12 +25,12 @@ void ActSpawnIcemaker(void) { ecs_entity_t e = item_spawn(ASSET_DEMO_ICEMAKER, 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; entity_set_position(e, dest->x, dest->y); - + debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM); } @@ -38,12 +38,12 @@ 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; entity_set_position(e, dest->x, dest->y); - + debug_replay_special_action(RPKIND_SPAWN_CHEST); } @@ -51,20 +51,34 @@ void ActSpawnBelt(void) { ecs_entity_t e = item_spawn(ASSET_BELT, 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; entity_set_position(e, dest->x, dest->y); - + debug_replay_special_action(RPKIND_SPAWN_BELT); } +void +ActSpawnDurabilityTest(void) { + ecs_entity_t e = item_spawn(ASSET_DEMO_ICEMAKER, 1); + 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; + entity_set_position(e, dest->x, dest->y); + + Item *it = ecs_get_mut(world_ecs(), e, Item); + it->durability = (float)(rand() % 100) / 100.0f; +} + void ActSpawnFurnace(void) { ecs_entity_t e = item_spawn(ASSET_FURNACE, 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; @@ -75,7 +89,7 @@ void ActSpawnDemoHouseItem(void) { ecs_entity_t e = item_spawn(ASSET_BLUEPRINT, 1); 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; @@ -87,7 +101,7 @@ ActSpawnCirclingDriver(void) { ecs_entity_t plr = camera_get().ent_id; ecs_entity_t ve = vehicle_spawn(EVEH_CAR); ecs_entity_t e = entity_spawn(EKIND_DEMO_NPC); - + Position const *origin = ecs_get(world_ecs(), plr, Position); Position *veh_dest = ecs_get_mut(world_ecs(), ve, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position); @@ -95,16 +109,16 @@ ActSpawnCirclingDriver(void) { *dest = *origin; entity_set_position(ve, veh_dest->x, veh_dest->y); entity_set_position(e, dest->x, dest->y); - + Input *input = ecs_get_mut(world_ecs(), e, Input); zpl_zero_item(input); input->x = input->y = 1.0f; - + Vehicle *veh = ecs_get_mut(world_ecs(), ve, Vehicle); veh->seats[0] = e; - + ecs_set(world_ecs(), e, IsInVehicle, { .veh = ve }); - + debug_replay_special_action(RPKIND_SPAWN_CIRCLING_DRIVER); } @@ -114,14 +128,14 @@ ActPlaceIceRink(void) { block_id watr_id = blocks_find(ASSET_WATER); Position const *p = ecs_get(world_ecs(), plr, Position); float const bs = WORLD_BLOCK_SIZE; - + for (int y = 0; y < 100; y++) { 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_chunk_place_block(l.chunk_id, l.id, watr_id); } } - + debug_replay_special_action(RPKIND_PLACE_ICE_RINK); } @@ -130,13 +144,13 @@ ActEraseWorldChanges(void) { ecs_entity_t plr = camera_get().ent_id; Position const *p = ecs_get(world_ecs(), plr, Position); float const bs = WORLD_BLOCK_SIZE; - + for (int y = 0; y < 100; y++) { for (int x = 0; x < 100; x++) { world_chunk_destroy_block((p->x - (x*bs)/2.0f), (p->y - (y*bs)/2.0f), true); } } - + debug_replay_special_action(RPKIND_PLACE_ERASE_CHANGES); } @@ -203,22 +217,22 @@ void ActReplaySaveAs(void) { if (!records) return; char const *workdir = GetWorkingDirectory(); - + sfd_Options sfd = { .title = "Save Macro", .path = "art", .filter_name = "eco2d Macro", .filter = "*.dem", }; - + char const *path = sfd_save_dialog(&sfd); ChangeDirectory(workdir); - + if (path) { zpl_strcpy(replay_filename, zpl_bprintf("%s.dem", path)); debug_replay_store(); } - + } void @@ -232,17 +246,17 @@ ActReplaySave(void) { void ActReplayLoad(void) { char const *workdir = GetWorkingDirectory(); - + sfd_Options sfd = { .title = "Load Macro", .path = "art", .filter_name = "eco2d Macro", .filter = "*.dem", }; - + char const *path = sfd_open_dialog(&sfd); ChangeDirectory(workdir); - + if (path) { zpl_zero_size(replay_filename, sizeof(replay_filename)); zpl_strcpy(replay_filename, path); @@ -258,18 +272,18 @@ void ActSpawnDemoNPCs(void) { if (!demo_npcs) zpl_array_init(demo_npcs, zpl_heap()); if (zpl_array_count(demo_npcs) >= 100000) return; - + for (uint32_t i = 0; i < 1000; i++) { uint64_t e = entity_spawn(EKIND_DEMO_NPC); ecs_add(world_ecs(), e, DemoNPC); Position *pos = ecs_get_mut(world_ecs(), e, Position); pos->x=(float)(rand() % world_dim()); - pos->y=(float)(rand() % world_dim()); - + pos->y=(float)(rand() % world_dim()); + Velocity *v = ecs_get_mut(world_ecs(), e, Velocity); v->x = (float)((rand()%3-1) * 10); v->y = (float)((rand()%3-1) * 10); - + zpl_array_append(demo_npcs, e); } } @@ -277,9 +291,9 @@ ActSpawnDemoNPCs(void) { void ActDespawnDemoNPCs(void) { if (!demo_npcs) return; - + entity_batch_despawn(demo_npcs, zpl_array_count(demo_npcs)); - + zpl_array_free(demo_npcs); demo_npcs = 0; } diff --git a/code/foundation/src/gui/inventory.c b/code/foundation/src/gui/inventory.c index 8c71bb1..ab06325 100644 --- a/code/foundation/src/gui/inventory.c +++ b/code/foundation/src/gui/inventory.c @@ -1,11 +1,11 @@ typedef struct { uint8_t selected_item; bool drop_item; - + bool item_is_held; uint8_t held_item_idx; Item held_item; - + bool is_inside; bool storage_action; bool swap; @@ -26,26 +26,26 @@ void inventory_draw_panel(entity_view *e, bool is_player, float sx, float sy){ 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; Item *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){ @@ -79,22 +79,30 @@ void inventory_draw_panel(entity_view *e, bool is_player, float sx, float sy){ } 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); + } + + if (item->quantity > 1) { + DrawTextEco(zpl_bprintf("%d", item->quantity), x+5, y+5, 16, RAYWHITE, 0.0f); + } + + if (item->quantity > 0 && item->durability < 1.0f) { + DrawRectangleEco(x, y+56, 64, 8, BLACK); + DrawRectangleEco(x, y+56, 64*item->durability, 8, BlendColor(RED, GREEN, item->durability)); } } x += 64; - + if ((i+1) % inv_cols == 0) { x = sx; y += 64; } } - + // NOTE(zaklaus): switch it off if is_player if (is_player) inv_is_storage_action = false; @@ -103,18 +111,18 @@ void inventory_draw_panel(entity_view *e, bool is_player, float sx, float sy){ void inventory_render_held_item(bool is_player){ inv_keystate *inv = (!is_player) ? &storage_inv : &player_inv; inv_keystate *inv2 = (is_player) ? &storage_inv : &player_inv; - + 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); - + 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; + inv_is_storage_action = inv == &storage_inv; } } } @@ -130,22 +138,22 @@ void inventory_draw() { 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); if (!e || !e->has_items) return; - + if (IsKeyPressed(KEY_TAB)) { inv_is_open = !inv_is_open; } - + if (!inv_is_open || build_is_in_draw_mode) { return; } - + 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); - + inventory_render_held_item(true); inventory_render_held_item(false); } diff --git a/code/foundation/src/utils/raylib_helpers.h b/code/foundation/src/utils/raylib_helpers.h index 1c3f0f7..7486443 100644 --- a/code/foundation/src/utils/raylib_helpers.h +++ b/code/foundation/src/utils/raylib_helpers.h @@ -10,6 +10,16 @@ static inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; } +static inline +Color BlendColor(Color a, Color b, float t) { + return (Color) { + .r = (uint8_t)(lerp((float)(a.r)/255.0f, (float)(b.r)/255.0f, t) * 255), + .g = (uint8_t)(lerp((float)(a.g)/255.0f, (float)(b.g)/255.0f, t) * 255), + .b = (uint8_t)(lerp((float)(a.b)/255.0f, (float)(b.b)/255.0f, t) * 255), + .a = (uint8_t)(lerp((float)(a.a)/255.0f, (float)(b.a)/255.0f, t) * 255), + }; +} + static inline Texture2D LoadTexEco(const char *name) { static char filename[128]; diff --git a/code/foundation/src/world/entity_view.c b/code/foundation/src/world/entity_view.c index 3ac3cc2..ed38e8b 100644 --- a/code/foundation/src/world/entity_view.c +++ b/code/foundation/src/world/entity_view.c @@ -31,6 +31,7 @@ pkt_desc pkt_entity_view_desc[] = { { PKT_KEEP_IF(entity_view, kind, EKIND_ITEM, 2) }, { PKT_UINT(entity_view, asset) }, { PKT_UINT(entity_view, quantity) }, + { PKT_HALF(entity_view, durability) }, { PKT_KEEP_IF(entity_view, kind, EKIND_DEVICE, 3) }, { PKT_UINT(entity_view, asset) }, diff --git a/code/foundation/src/world/entity_view.h b/code/foundation/src/world/entity_view.h index 6697218..97c6936 100644 --- a/code/foundation/src/world/entity_view.h +++ b/code/foundation/src/world/entity_view.h @@ -62,6 +62,7 @@ typedef struct entity_view { // NOTE(zaklaus): items, ... asset_id asset; uint32_t quantity; + float durability; // NOTE(zaklaus): device progress bar uint32_t progress_active; diff --git a/code/foundation/src/world/world.c b/code/foundation/src/world/world.c index 56457f2..18548a0 100644 --- a/code/foundation/src/world/world.c +++ b/code/foundation/src/world/world.c @@ -63,6 +63,7 @@ entity_view *world_build_entity_view(int64_t e) { Item const* dr = ecs_get(world_ecs(), e, Item); view.asset = dr->kind; view.quantity = dr->quantity; + view.durability = dr->durability; } if (ecs_get(world_ecs(), e, Device)) { diff --git a/code/games/sandbox/src/renderer.c b/code/games/sandbox/src/renderer.c index c02fcfe..bdcd173 100644 --- a/code/games/sandbox/src/renderer.c +++ b/code/games/sandbox/src/renderer.c @@ -110,7 +110,15 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) { 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)); - DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f); + + if (data->quantity > 1) { + DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f); + } + + if (data->durability < 1.0f) { + DrawRectangleEco(x, y+32, 4, 32, BlendColor(RED, GREEN, data->durability)); + DrawRectangleEco(x, y+32, 4, 32*(1.0f-data->durability), ColorAlpha(BLACK, data->tran_time)); + } }break; default:break; }