game: health, pain and regen

isolation_bkp/dynres
Dominik Madarász 2021-07-27 18:34:31 +02:00
parent 5212aedf92
commit 2370bd4ea0
15 changed files with 84 additions and 9 deletions

BIN
art/gen/lava.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

View File

@ -37,6 +37,9 @@ typedef struct entity_view {
float tx; float tx;
float ty; float ty;
float hp;
float max_hp;
// TODO(zaklaus): Find a way to stream dynamic arrays // TODO(zaklaus): Find a way to stream dynamic arrays
uint8_t blocks_used; uint8_t blocks_used;
uint8_t blocks[256]; uint8_t blocks[256];

View File

@ -14,6 +14,7 @@ void game_shutdown();
void game_request_close(); void game_request_close();
uint8_t game_is_running(); uint8_t game_is_running();
int8_t game_is_networked(); int8_t game_is_networked();
float game_time();
//~ NOTE(zaklaus): game events //~ NOTE(zaklaus): game events
void game_input(); void game_input();

View File

@ -4,7 +4,8 @@
#define BLOCK_INVALID 0xF #define BLOCK_INVALID 0xF
typedef enum { typedef enum {
BLOCK_FLAG_COLLISION = (1 << 1) BLOCK_FLAG_COLLISION = (1 << 1),
BLOCK_FLAG_HAZARD = (1 << 2),
} block_flags; } block_flags;
#include "blocks_info.h" #include "blocks_info.h"

View File

@ -5,6 +5,7 @@ typedef enum {
BLOCK_KIND_GROUND, BLOCK_KIND_GROUND,
BLOCK_KIND_DIRT, BLOCK_KIND_DIRT,
BLOCK_KIND_WATER, BLOCK_KIND_WATER,
BLOCK_KIND_LAVA,
BLOCK_KIND_WALL, BLOCK_KIND_WALL,
BLOCK_KIND_HILL, BLOCK_KIND_HILL,
BLOCK_KIND_HILL_SNOW, BLOCK_KIND_HILL_SNOW,

View File

@ -15,6 +15,8 @@ pkt_desc pkt_entity_view_desc[] = {
{ PKT_HALF(entity_view, vy) }, { PKT_HALF(entity_view, vy) },
//{ PKT_SKIP_IF(entity_view, blocks_used, 0, 1) }, // NOTE(zaklaus): skip blocks for anything else //{ PKT_SKIP_IF(entity_view, blocks_used, 0, 1) }, // NOTE(zaklaus): skip blocks for anything else
{ PKT_ARRAY(entity_view, blocks) }, { PKT_ARRAY(entity_view, blocks) },
{ PKT_HALF(entity_view, hp) },
{ PKT_HALF(entity_view, max_hp) },
{ PKT_END }, { PKT_END },
}; };

View File

@ -104,6 +104,10 @@ void flecs_dash_init() {
ecs_set(world_ecs(), 0, EcsDashServer, {.port = 27001}); ecs_set(world_ecs(), 0, EcsDashServer, {.port = 27001});
} }
float game_time() {
return zpl_time_rel();
}
void game_init(game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled) { void game_init(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_mode = play_mode;
platform_init(); platform_init();

View File

@ -34,6 +34,9 @@ Texture2D texgen_build_block(uint32_t biome, uint32_t kind) {
case BLOCK_KIND_WATER:{ case BLOCK_KIND_WATER:{
return LoadImageEco("water"); return LoadImageEco("water");
}break; }break;
case BLOCK_KIND_LAVA:{
return LoadImageEco("lava");
}break;
} }
} }
} }

View File

@ -190,7 +190,7 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
uint16_t font_size = (uint16_t)lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom); uint16_t font_size = (uint16_t)lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom);
float font_spacing = 1.1f; float font_spacing = 1.1f;
float title_bg_offset = 4; float title_bg_offset = 4;
float fixed_title_offset = 2; float fixed_title_offset = 8;
switch (data->kind) { switch (data->kind) {
case EKIND_DEMO_NPC: { case EKIND_DEMO_NPC: {
@ -207,13 +207,15 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
case EKIND_PLAYER: { case EKIND_PLAYER: {
float x = data->x; float x = data->x;
float y = data->y; float y = data->y;
float health = (data->hp / data->max_hp);
#if 1 #if 1
const char *title = TextFormat("Player %d", key); const char *title = TextFormat("Player %d", key);
int title_w = MeasureTextEco(title, font_size, font_spacing); int title_w = MeasureTextEco(title, font_size, font_spacing);
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time)); DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time));
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time));
DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing); DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing);
#endif #endif
DrawCircleEco(x, y, size, ColorAlpha(RED, data->tran_time)); DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time));
}break; }break;
default:break; default:break;
} }

View File

@ -10,6 +10,8 @@
#include "modules/systems.h" #include "modules/systems.h"
#include "zpl.h" #include "zpl.h"
#define PLAYER_MAX_HP 100.0f
uint64_t player_spawn(char *name) { uint64_t player_spawn(char *name) {
ecs_entity_t e = entity_spawn(NULL, EKIND_PLAYER); ecs_entity_t e = entity_spawn(NULL, EKIND_PLAYER);
@ -23,6 +25,7 @@ uint64_t player_spawn(char *name) {
ecs_add(world_ecs(), e, EcsClient); ecs_add(world_ecs(), e, EcsClient);
ecs_set(world_ecs(), e, ClientInfo, {0}); ecs_set(world_ecs(), e, ClientInfo, {0});
ecs_set(world_ecs(), e, Input, {0}); ecs_set(world_ecs(), e, Input, {0});
ecs_set(world_ecs(), e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP});
ecs_add(world_ecs(), e, Player); ecs_add(world_ecs(), e, Player);
librg_entity_owner_set(world_tracker(), e, (int64_t)e); librg_entity_owner_set(world_tracker(), e, (int64_t)e);

View File

@ -7,4 +7,5 @@ static block blocks[] = {
{.name = "base-hill", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL, .biome = 0, .symbol = '^', .drag = 1.0f }, {.name = "base-hill", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL, .biome = 0, .symbol = '^', .drag = 1.0f },
{.name = "base-hill-snow", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL_SNOW, .biome = 0, .symbol = '*', .drag = 1.0f }, {.name = "base-hill-snow", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL_SNOW, .biome = 0, .symbol = '*', .drag = 1.0f },
{.name = "base-water", .flags = 0, .kind = BLOCK_KIND_WATER, .biome = 0, .symbol = '~', .drag = 0.11f }, {.name = "base-water", .flags = 0, .kind = BLOCK_KIND_WATER, .biome = 0, .symbol = '~', .drag = 0.11f },
{.name = "base-lava", .flags = BLOCK_FLAG_HAZARD, .kind = BLOCK_KIND_LAVA, .biome = 0, .symbol = '!', .drag = 6.2f },
}; };

View File

@ -14,30 +14,35 @@ static world_data world = {0};
static Components const *ecs_components; static Components const *ecs_components;
entity_view world_build_entity_view(int64_t e) { entity_view world_build_entity_view(int64_t e) {
ECS_IMPORT(world_ecs(), Components); ECS_IMPORT(world.ecs, Components);
entity_view view = {0}; entity_view view = {0};
const Classify *classify = ecs_get(world_ecs(), e, Classify); const Classify *classify = ecs_get(world.ecs, e, Classify);
assert(classify); assert(classify);
view.kind = classify->id; view.kind = classify->id;
const Position *pos = ecs_get(world_ecs(), e, Position); const Position *pos = ecs_get(world.ecs, e, Position);
if (pos) { if (pos) {
view.x = pos->x; view.x = pos->x;
view.y = pos->y; view.y = pos->y;
} }
const Velocity *vel = ecs_get(world_ecs(), e, Velocity); const Velocity *vel = ecs_get(world.ecs, e, Velocity);
if (vel) { if (vel) {
view.flag |= EFLAG_INTERP; view.flag |= EFLAG_INTERP;
view.vx = vel->x; view.vx = vel->x;
view.vy = vel->y; view.vy = vel->y;
} }
const Health *health = ecs_get(world.ecs, e, Health);
if (health) {
view.hp = health->hp;
view.max_hp = health->max_hp;
}
if (ecs_get(world_ecs(), e, Chunk)) { if (ecs_get(world.ecs, e, Chunk)) {
Chunk *chpos = ecs_get_mut(world_ecs(), e, Chunk, 0); Chunk *chpos = ecs_get_mut(world.ecs, e, Chunk, 0);
view.x = chpos->x; view.x = chpos->x;
view.y = chpos->y; view.y = chpos->y;
view.blocks_used = 1; view.blocks_used = 1;

View File

@ -130,6 +130,7 @@ int32_t worldgen_test(world_data *wld) {
uint8_t grnd_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_GROUND); uint8_t grnd_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_GROUND);
uint8_t dirt_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_DIRT); uint8_t dirt_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_DIRT);
uint8_t watr_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER); uint8_t watr_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER);
uint8_t lava_id = blocks_find(BLOCK_BIOME_DEV, BLOCK_KIND_LAVA);
srand(world->seed); srand(world->seed);
@ -147,6 +148,13 @@ int32_t worldgen_test(world_data *wld) {
} }
#endif #endif
// lava
#if 1
for (int i=0; i<RAND_RANGE(48, 62); i++) {
world_fill_rect_anchor(lava_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80);
}
#endif
// hills // hills
#if 1 #if 1

View File

@ -39,6 +39,7 @@ ECS_STRUCT(Health, {
// NOTE(zaklaus): Intentionally global, to allow for creative use of damage combos // NOTE(zaklaus): Intentionally global, to allow for creative use of damage combos
float pain_time; float pain_time;
float heal_time;
}); });
ECS_STRUCT(Classify, { ECS_STRUCT(Classify, {

View File

@ -4,6 +4,7 @@
#include "world/world.h" #include "world/world.h"
#include "world/blocks.h" #include "world/blocks.h"
#include "profiler.h" #include "profiler.h"
#include "game.h"
#define PHY_BLOCK_COLLISION 1 #define PHY_BLOCK_COLLISION 1
#define PHY_WALK_DRAG 0.12 #define PHY_WALK_DRAG 0.12
@ -168,6 +169,43 @@ void DemoPlaceIceBlock(ecs_iter_t *it) {
} }
} }
#define HAZARD_BLOCK_TIME 1.0f
#define HAZARD_BLOCK_DMG 5.0f
void HurtOnHazardBlock(ecs_iter_t *it) {
Position *p = ecs_column(it, Position, 1);
Health *h = ecs_column(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.block_id) & BLOCK_FLAG_HAZARD) {
if (h->pain_time < game_time()) {
h->pain_time = game_time() + HAZARD_BLOCK_TIME;
h->hp -= HAZARD_BLOCK_DMG;
h->hp = zpl_max(0.0f, h->hp);
}
}
}
}
#define HP_REGEN_TIME 2.0f
#define HP_REGEN_PAIN_COOLDOWN 5.0f
#define HP_REGEN_RECOVERY 15.0f
void RegenerateHP(ecs_iter_t *it) {
Health *h = ecs_column(it, Health, 1);
for (int i = 0; i < it->count; i++) {
if (h->pain_time < game_time() - HP_REGEN_PAIN_COOLDOWN) {
if (h->heal_time < game_time() && h->hp < h->max_hp) {
h->heal_time = game_time() + HP_REGEN_TIME;
h->hp += HP_REGEN_RECOVERY;
h->hp = zpl_min(h->max_hp, h->hp);
}
}
}
}
void SystemsImport(ecs_world_t *ecs) { void SystemsImport(ecs_world_t *ecs) {
ECS_MODULE(ecs, Systems); ECS_MODULE(ecs, Systems);
ECS_IMPORT(ecs, Components); ECS_IMPORT(ecs, Components);
@ -177,6 +215,8 @@ void SystemsImport(ecs_world_t *ecs) {
ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.EcsDemoNPC); ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.EcsDemoNPC);
ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, components.Position, components.Velocity); ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, components.Position, components.Velocity);
ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health);
ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health);
ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, components.Position, components.Velocity); ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, components.Position, components.Velocity);
//ECS_SYSTEM(ecs, PushOutOverlappingEntities, EcsOnValidate, components.Position, Velocity); //ECS_SYSTEM(ecs, PushOutOverlappingEntities, EcsOnValidate, components.Position, Velocity);