diff --git a/code/foundation/src/assets_ids.h b/code/foundation/src/assets_ids.h index 994d4b7..ae0aa14 100644 --- a/code/foundation/src/assets_ids.h +++ b/code/foundation/src/assets_ids.h @@ -20,7 +20,6 @@ X(ASSET_BLUEPRINT)\ X(ASSET_BLUEPRINT_DEMO_HOUSE)\ X(ASSET_BLUEPRINT_END)\ - X(ASSET_MOB)\ X(ASSET_FENCE)\ X(ASSET_DEV)\ X(ASSET_GROUND)\ diff --git a/code/foundation/src/dev/debug_ui.c b/code/foundation/src/dev/debug_ui.c index 2674fa8..9bbcb9c 100644 --- a/code/foundation/src/dev/debug_ui.c +++ b/code/foundation/src/dev/debug_ui.c @@ -163,7 +163,6 @@ static debug_item items[] = { .is_collapsed = false } }, - { .kind = DITEM_BUTTON, .name = "spawn mobs", .on_click = ActSpawnMobs }, { .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar }, { .kind = DITEM_BUTTON, .name = "place ice rink", .on_click = ActPlaceIceRink }, { .kind = DITEM_BUTTON, .name = "erase world changes", .on_click = ActEraseWorldChanges }, diff --git a/code/foundation/src/dev/debug_ui_actions.c b/code/foundation/src/dev/debug_ui_actions.c index 31eb19d..1b8e540 100644 --- a/code/foundation/src/dev/debug_ui_actions.c +++ b/code/foundation/src/dev/debug_ui_actions.c @@ -54,32 +54,6 @@ ActSpawnSelItem(void) { entity_set_position(e, origin->x, origin->y); } -void -ActSpawnMobs(void) { - ecs_entity_t plr = camera_get().ent_id; - Position const* origin = ecs_get(world_ecs(), plr, Position); - - const uint32_t w = 12*WORLD_BLOCK_SIZE; - const uint32_t h = 12*WORLD_BLOCK_SIZE; - uint32_t x = (uint32_t)origin->x - w/2; - uint32_t y = (uint32_t)origin->y - h/2; - - for (uint32_t cy=y; cy= world_dim()) continue; - if (cy >= world_dim()) continue; - - if ((cy == y || cy == (y + h-WORLD_BLOCK_SIZE)) || - (cx == x || cx == (x + w-WORLD_BLOCK_SIZE))) { - ecs_entity_t e = entity_spawn_id(ASSET_MOB); - entity_set_position(e, (float)cx, (float)cy); - - ecs_add(world_ecs(), e, MobMelee); - } - } - } -} - void ActSpawnCirclingDriver(void) { ecs_entity_t plr = camera_get().ent_id; diff --git a/code/foundation/src/gen/texgen_fallback.c b/code/foundation/src/gen/texgen_fallback.c index 64562e4..e1c4f55 100644 --- a/code/foundation/src/gen/texgen_fallback.c +++ b/code/foundation/src/gen/texgen_fallback.c @@ -56,9 +56,6 @@ Texture2D texgen_build_sprite_fallback(asset_id id) { case ASSET_CRAFTBENCH: return LoadTexEco("craftbench"); case ASSET_SPLITTER: return LoadTexEco("item_splitter"); case ASSET_ASSEMBLER: return LoadTexEco("assembler"); - - // Mobs - case ASSET_MOB: return LoadTexEco("enemy1"); default: break; } diff --git a/code/foundation/src/gui/tooltip.c b/code/foundation/src/gui/tooltip.c index 45dc08f..c0b8776 100644 --- a/code/foundation/src/gui/tooltip.c +++ b/code/foundation/src/gui/tooltip.c @@ -1,255 +1,254 @@ -// Tooltip system with multilevel modal support - -typedef struct _tooltip { - const char *name; - const char *content; - const char **links; -} tooltip; - -static tooltip *tooltips = 0; - -//~ registration - -void tooltip_register(tooltip desc) { - if (!tooltips) { - zpl_array_init(tooltips, zpl_heap()); - } - - desc.links = 0; - zpl_array_append(tooltips, desc); -} - -void tooltip_destroy_all(void) { - if (!tooltips) return; - - for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { - tooltip *tp = (tooltips + i); - - if (tp->links) { - zpl_array_free(tp->links); - } - } - - zpl_array_free(tooltips); -} - -void tooltip_build_links(void) { - for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { - tooltip *tp = (tooltips + i); - - for (zpl_isize j = 0; j < zpl_array_count(tooltips); ++j) { - tooltip *linked_tp = (tooltips + j); - if (tp == linked_tp) - continue; - - if (strstr(tp->content, linked_tp->name)) { - if (!tp->links) { - zpl_array_init(tp->links, zpl_heap()); - } - - zpl_array_append(tp->links, linked_tp->name); - } - } - } -} - -void tooltip_register_defaults(void) { - // test - tooltip_register( (tooltip) { .name = "ASSET_WOOD", .content = "Used as a building material or fuel for the ASSET_FURNACE." } ); - tooltip_register( (tooltip) { .name = "ASSET_FURNACE", .content = "Producer used to smelt ASSET_IRON_ORE into ASSET_IRON_INGOT." } ); - tooltip_register( (tooltip) { .name = "ASSET_IRON_ORE", .content = "Natural resource that can be smelted in ASSET_FURNACE." } ); - tooltip_register( (tooltip) { .name = "ASSET_IRON_INGOT", .content = "Used as a building material. It is smelted from ASSET_IRON_ORE." } ); - tooltip_register( (tooltip) { .name = "ASSET_SCREWS", .content = "Used as a building material. It is crafted from ASSET_IRON_PLATES." } ); - tooltip_register( (tooltip) { .name = "ASSET_MOB", .content = "Enemy hunting player down." } ); - tooltip_register( (tooltip) { .name = "craft", .content = "Crafting is the process of constructing tools, items, and blocks." } ); - tooltip_register( (tooltip) { .name = "smelt", .content = "Smelting is a process of applying heat to ore, to extract a base metal. It is a form of extractive metallurgy. It is used to extract many metals from their ores, including silver, iron, copper, and other base metals." } ); -} - -//~ rendering - -#define TOOLTIP_MOUSE_DIST 400.0f - -typedef struct _tooltip_node { - float xpos, ypos; - tooltip *desc; - struct _tooltip_node *next; -} tooltip_node; - -static tooltip_node main_tooltip = { 0 }; -static bool tooltip__should_stay_open = false; - -tooltip *tooltip_find_desc(const char *name) { - for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { - tooltip *tp = (tooltips + i); - - if (!strcmp(tp->name, name)) - return tp; - } - - return 0; -} - -const char *tooltip_find_desc_contents(const char *name) { - if (!tooltips) return 0; - - for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { - tooltip *tp = (tooltips + i); - - if (!strcmp(tp->name, name)) - return tp->content; - } - - return 0; -} - -void tooltip_clear(void); - -void tooltip_show(const char* name, float xpos, float ypos) { - if (!tooltips) return; - - tooltip *desc = tooltip_find_desc(name); - if (!name) return; - - tooltip_clear(); - - main_tooltip = (tooltip_node) { - .xpos = xpos, - .ypos = ypos, - .desc = desc, - .next = 0 - }; -} - -void tooltip_show_cursor(const char* name) { - Vector2 mpos = GetMousePosition(); - tooltip_show(name, mpos.x + 15, mpos.y + 15); -} - -void tooltip__clear_node(tooltip_node *node) { - if (node->next) { - tooltip__clear_node(node->next); - zpl_mfree(node->next); - } -} - -void tooltip_clear(void) { - tooltip__clear_node(&main_tooltip); - main_tooltip = (tooltip_node) {0}; -} - -void tooltip_draw_contents(tooltip *desc) { - if (!desc) return; - nk_layout_row_dynamic(game_ui, 0, 1); - nk_label_wrap(game_ui, desc->content); -} - -void tooltip__draw_node(tooltip_node *node) { - if (!node) return; - if (!node->desc) return; - - tooltip *desc = node->desc; - Vector2 mpos = GetMousePosition(); - - if (nk_begin_titled(game_ui, zpl_bprintf("%d%s", (int)node->xpos, desc->name), desc->name, nk_rect(node->xpos, node->ypos, 500, 3200), - NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_DYNAMIC | NK_WINDOW_TITLE | NK_WINDOW_MOVABLE)) { - tooltip_draw_contents(desc); - - if (desc->links) { - nk_label(game_ui, "See Also:", NK_TEXT_LEFT); - nk_layout_row_dynamic(game_ui, 20, 2); - - for (zpl_isize i = 0; i < zpl_array_count(desc->links); ++i) { - if (nk_button_label(game_ui, desc->links[i])) { - if (node->next) tooltip__clear_node(node->next); - if (!node->next) node->next = zpl_malloc(sizeof(tooltip_node)); - *node->next = (tooltip_node) { - .xpos = mpos.x+15, - .ypos = mpos.y+15, - .desc = tooltip_find_desc(desc->links[i]), - .next = 0 - }; - } - } - } - - // suggest closing tooltip - struct nk_vec2 wpos = nk_window_get_position(game_ui); - struct nk_vec2 wsize = nk_window_get_content_region_size(game_ui); - struct nk_panel *wpanel = nk_window_get_panel(game_ui); - Vector2 tp_pos = (Vector2) { .x = wpos.x + wsize.x/2.0f, .y = wpos.y + wpanel->row.height / 2.0f }; - if (Vector2Distance(mpos, tp_pos) <= TOOLTIP_MOUSE_DIST) { - tooltip__should_stay_open = true; - } - -#if 0 - { - DrawCircleV(tp_pos, TOOLTIP_MOUSE_DIST, BLUE); - } -#endif - - nk_end(game_ui); - - // draw nested tooltip - if (node->next) { - tooltip__draw_node(node->next); - } - } -} - -void tooltip_draw(void) { - // draw tooltip - tooltip__draw_node(&main_tooltip); - - if (!tooltip__should_stay_open) { - tooltip_clear(); - } - - tooltip__should_stay_open = false; - - // draw search bar - float width = (float)GetScreenWidth(); - float height = (float)GetScreenHeight(); - - if (nk_begin(game_ui, "#searchbar", nk_rect(width / 2.0f - 200, 15.f, 400, 600), NK_WINDOW_DYNAMIC | NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR)) { - { - static int len=0; static char buffer[256] = { 0 }; - - - static bool show_all = false; - - if (len > 0) { - nk_layout_row_dynamic(game_ui, 15, 1); - if (nk_button_label(game_ui, "clear all")) { - len = 0; - } - } - - nk_layout_row_dynamic(game_ui, 35, 1); - - if (!(nk_edit_string(game_ui, NK_EDIT_SIMPLE, buffer, &len, 255, nk_filter_ascii) & NK_WIDGET_STATE_ACTIVE) && len == 0 ) { - show_all = true; - } - buffer[len] = 0; - - if (len > 0 || show_all) { - if (nk_tree_push(game_ui, NK_TREE_TAB, "results", NK_MAXIMIZED)) { - for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { - tooltip *tp = (tooltips + i); - - if (strstr(tp->name, buffer) || show_all) { - if (nk_button_label(game_ui, tp->name)) { - tooltip_show_cursor(tp->name); - } - } - } - nk_tree_pop(game_ui); - } - } - - if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT) || len > 0) { - show_all = false; - } - } - nk_end(game_ui); - } -} +// Tooltip system with multilevel modal support + +typedef struct _tooltip { + const char *name; + const char *content; + const char **links; +} tooltip; + +static tooltip *tooltips = 0; + +//~ registration + +void tooltip_register(tooltip desc) { + if (!tooltips) { + zpl_array_init(tooltips, zpl_heap()); + } + + desc.links = 0; + zpl_array_append(tooltips, desc); +} + +void tooltip_destroy_all(void) { + if (!tooltips) return; + + for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { + tooltip *tp = (tooltips + i); + + if (tp->links) { + zpl_array_free(tp->links); + } + } + + zpl_array_free(tooltips); +} + +void tooltip_build_links(void) { + for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { + tooltip *tp = (tooltips + i); + + for (zpl_isize j = 0; j < zpl_array_count(tooltips); ++j) { + tooltip *linked_tp = (tooltips + j); + if (tp == linked_tp) + continue; + + if (strstr(tp->content, linked_tp->name)) { + if (!tp->links) { + zpl_array_init(tp->links, zpl_heap()); + } + + zpl_array_append(tp->links, linked_tp->name); + } + } + } +} + +void tooltip_register_defaults(void) { + // test + tooltip_register( (tooltip) { .name = "ASSET_WOOD", .content = "Used as a building material or fuel for the ASSET_FURNACE." } ); + tooltip_register( (tooltip) { .name = "ASSET_FURNACE", .content = "Producer used to smelt ASSET_IRON_ORE into ASSET_IRON_INGOT." } ); + tooltip_register( (tooltip) { .name = "ASSET_IRON_ORE", .content = "Natural resource that can be smelted in ASSET_FURNACE." } ); + tooltip_register( (tooltip) { .name = "ASSET_IRON_INGOT", .content = "Used as a building material. It is smelted from ASSET_IRON_ORE." } ); + tooltip_register( (tooltip) { .name = "ASSET_SCREWS", .content = "Used as a building material. It is crafted from ASSET_IRON_PLATES." } ); + tooltip_register( (tooltip) { .name = "craft", .content = "Crafting is the process of constructing tools, items, and blocks." } ); + tooltip_register( (tooltip) { .name = "smelt", .content = "Smelting is a process of applying heat to ore, to extract a base metal. It is a form of extractive metallurgy. It is used to extract many metals from their ores, including silver, iron, copper, and other base metals." } ); +} + +//~ rendering + +#define TOOLTIP_MOUSE_DIST 400.0f + +typedef struct _tooltip_node { + float xpos, ypos; + tooltip *desc; + struct _tooltip_node *next; +} tooltip_node; + +static tooltip_node main_tooltip = { 0 }; +static bool tooltip__should_stay_open = false; + +tooltip *tooltip_find_desc(const char *name) { + for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { + tooltip *tp = (tooltips + i); + + if (!strcmp(tp->name, name)) + return tp; + } + + return 0; +} + +const char *tooltip_find_desc_contents(const char *name) { + if (!tooltips) return 0; + + for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { + tooltip *tp = (tooltips + i); + + if (!strcmp(tp->name, name)) + return tp->content; + } + + return 0; +} + +void tooltip_clear(void); + +void tooltip_show(const char* name, float xpos, float ypos) { + if (!tooltips) return; + + tooltip *desc = tooltip_find_desc(name); + if (!name) return; + + tooltip_clear(); + + main_tooltip = (tooltip_node) { + .xpos = xpos, + .ypos = ypos, + .desc = desc, + .next = 0 + }; +} + +void tooltip_show_cursor(const char* name) { + Vector2 mpos = GetMousePosition(); + tooltip_show(name, mpos.x + 15, mpos.y + 15); +} + +void tooltip__clear_node(tooltip_node *node) { + if (node->next) { + tooltip__clear_node(node->next); + zpl_mfree(node->next); + } +} + +void tooltip_clear(void) { + tooltip__clear_node(&main_tooltip); + main_tooltip = (tooltip_node) {0}; +} + +void tooltip_draw_contents(tooltip *desc) { + if (!desc) return; + nk_layout_row_dynamic(game_ui, 0, 1); + nk_label_wrap(game_ui, desc->content); +} + +void tooltip__draw_node(tooltip_node *node) { + if (!node) return; + if (!node->desc) return; + + tooltip *desc = node->desc; + Vector2 mpos = GetMousePosition(); + + if (nk_begin_titled(game_ui, zpl_bprintf("%d%s", (int)node->xpos, desc->name), desc->name, nk_rect(node->xpos, node->ypos, 500, 3200), + NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_DYNAMIC | NK_WINDOW_TITLE | NK_WINDOW_MOVABLE)) { + tooltip_draw_contents(desc); + + if (desc->links) { + nk_label(game_ui, "See Also:", NK_TEXT_LEFT); + nk_layout_row_dynamic(game_ui, 20, 2); + + for (zpl_isize i = 0; i < zpl_array_count(desc->links); ++i) { + if (nk_button_label(game_ui, desc->links[i])) { + if (node->next) tooltip__clear_node(node->next); + if (!node->next) node->next = zpl_malloc(sizeof(tooltip_node)); + *node->next = (tooltip_node) { + .xpos = mpos.x+15, + .ypos = mpos.y+15, + .desc = tooltip_find_desc(desc->links[i]), + .next = 0 + }; + } + } + } + + // suggest closing tooltip + struct nk_vec2 wpos = nk_window_get_position(game_ui); + struct nk_vec2 wsize = nk_window_get_content_region_size(game_ui); + struct nk_panel *wpanel = nk_window_get_panel(game_ui); + Vector2 tp_pos = (Vector2) { .x = wpos.x + wsize.x/2.0f, .y = wpos.y + wpanel->row.height / 2.0f }; + if (Vector2Distance(mpos, tp_pos) <= TOOLTIP_MOUSE_DIST) { + tooltip__should_stay_open = true; + } + +#if 0 + { + DrawCircleV(tp_pos, TOOLTIP_MOUSE_DIST, BLUE); + } +#endif + + nk_end(game_ui); + + // draw nested tooltip + if (node->next) { + tooltip__draw_node(node->next); + } + } +} + +void tooltip_draw(void) { + // draw tooltip + tooltip__draw_node(&main_tooltip); + + if (!tooltip__should_stay_open) { + tooltip_clear(); + } + + tooltip__should_stay_open = false; + + // draw search bar + float width = (float)GetScreenWidth(); + float height = (float)GetScreenHeight(); + + if (nk_begin(game_ui, "#searchbar", nk_rect(width / 2.0f - 200, 15.f, 400, 600), NK_WINDOW_DYNAMIC | NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR)) { + { + static int len=0; static char buffer[256] = { 0 }; + + + static bool show_all = false; + + if (len > 0) { + nk_layout_row_dynamic(game_ui, 15, 1); + if (nk_button_label(game_ui, "clear all")) { + len = 0; + } + } + + nk_layout_row_dynamic(game_ui, 35, 1); + + if (!(nk_edit_string(game_ui, NK_EDIT_SIMPLE, buffer, &len, 255, nk_filter_ascii) & NK_WIDGET_STATE_ACTIVE) && len == 0 ) { + show_all = true; + } + buffer[len] = 0; + + if (len > 0 || show_all) { + if (nk_tree_push(game_ui, NK_TREE_TAB, "results", NK_MAXIMIZED)) { + for (zpl_isize i = 0; i < zpl_array_count(tooltips); ++i) { + tooltip *tp = (tooltips + i); + + if (strstr(tp->name, buffer) || show_all) { + if (nk_button_label(game_ui, tp->name)) { + tooltip_show_cursor(tp->name); + } + } + } + nk_tree_pop(game_ui); + } + } + + if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT) || len > 0) { + show_all = false; + } + } + nk_end(game_ui); + } +} diff --git a/code/foundation/src/models/entity.c b/code/foundation/src/models/entity.c index 940d79a..2debe0a 100644 --- a/code/foundation/src/models/entity.c +++ b/code/foundation/src/models/entity.c @@ -44,7 +44,6 @@ void entity_default_spawnlist(void) { entity_add_spawndef(ASSET_SPLITTER, splitter_spawn); entity_add_spawndef(ASSET_ASSEMBLER, assembler_spawn); entity_add_spawndef(ASSET_CREATURE, creature_spawn); - entity_add_spawndef(ASSET_MOB, mob_spawn); entity_add_spawndef_data(ASSET_BLUEPRINT, blueprint_spawn_udata); } diff --git a/code/foundation/src/models/prefabs/prefabs_list.c b/code/foundation/src/models/prefabs/prefabs_list.c index 9e885db..302b6e3 100644 --- a/code/foundation/src/models/prefabs/prefabs_list.c +++ b/code/foundation/src/models/prefabs/prefabs_list.c @@ -118,13 +118,3 @@ uint64_t storage_spawn(void) { //------------------------------------------------------------------------ -uint64_t mob_spawn(void) { - ecs_entity_t e = entity_spawn(EKIND_MONSTER); - - ecs_add(world_ecs(), e, Mob); - ecs_set(world_ecs(), e, Health, { 60, 60, 0 }); - ecs_set(world_ecs(), e, PhysicsBody, { .kind = PHYS_AABB, .mass = 1.0f }); - ecs_set(world_ecs(), e, Sprite, { .frame = 101 + (rand()%3) }); - - return (uint64_t)e; -} diff --git a/code/games/survival/src/game.c b/code/games/survival/src/game.c index ef9b7b5..3516659 100644 --- a/code/games/survival/src/game.c +++ b/code/games/survival/src/game.c @@ -83,8 +83,23 @@ void mob_systems(ecs_world_t *ecs) { ECS_OBSERVER(ecs, MobOnDead, EcsOnAdd, components.Mob, components.Sprite, components.Velocity, components.Dead); } -void game_init(bool new_db) { +uint64_t mob_spawn(void) { + ecs_entity_t e = entity_spawn(EKIND_MONSTER); + ecs_add(world_ecs(), e, Mob); + ecs_set(world_ecs(), e, Health, { 60, 60, 0 }); + ecs_set(world_ecs(), e, PhysicsBody, { .kind = PHYS_AABB, .mass = 1.0f }); + ecs_set(world_ecs(), e, Sprite, { .frame = 101 + (rand()%3) }); + + return (uint64_t)e; +} + +void game_init(bool new_db) { + if (new_db) { + assets_new("MOB"); + } + + entity_add_spawndef(ASSET_MOB, mob_spawn); } void game_input() { diff --git a/code/games/survival/src/game.h b/code/games/survival/src/game.h index 6fa40d2..eab738b 100644 --- a/code/games/survival/src/game.h +++ b/code/games/survival/src/game.h @@ -1,7 +1,11 @@ -#pragma once - -enum { - SURV_CODE_SHOW_NOTIF, -}; - -void game_setup_ecs(); +#pragma once + +enum { + SURV_CODE_SHOW_NOTIF, +}; + +enum { + ASSET_MOB = NEXT_FREE_ASSET, +}; + +void game_setup_ecs(); diff --git a/code/games/survival/src/texgen.c b/code/games/survival/src/texgen.c index ce6df91..1c41dec 100644 --- a/code/games/survival/src/texgen.c +++ b/code/games/survival/src/texgen.c @@ -2,10 +2,14 @@ #include "world/world.h" #include "zpl.h" #include "utils/raylib_helpers.h" +#include "game.h" Texture2D texgen_build_anim(asset_id id, int64_t counter) { (void)counter; switch (id) { + + // Mobs + case ASSET_MOB: return LoadTexEco("enemy1"); default: return texgen_build_anim_fallback(id, counter); break; } }