diff --git a/code/foundation/src/models/components.h b/code/foundation/src/models/components.h index 016bd34..04b4e7d 100644 --- a/code/foundation/src/models/components.h +++ b/code/foundation/src/models/components.h @@ -260,6 +260,7 @@ typedef struct { typedef struct { uint8_t damage; float origin_x, origin_y; + ecs_entity_t owner; } WeaponProjectile; #define _COMPS\ diff --git a/code/games/survival/src/game.c b/code/games/survival/src/game.c index fcddebd..d904497 100644 --- a/code/games/survival/src/game.c +++ b/code/games/survival/src/game.c @@ -8,7 +8,12 @@ #include "gui/notifications.h" +float get_rand_between(float min, float max) { + return ((float)rand() / (float)RAND_MAX) * (max - min) + min; +} + static ecs_query_t *ecs_mobpos_query = NULL; +static ecs_query_t *ecs_pawn_query = NULL; // custom systems #include "system_mob.c" @@ -19,9 +24,11 @@ void mob_systems(ecs_world_t *ecs) { ECS_SYSTEM(ecs, MobMovement, EcsPostUpdate, components.Velocity, components.Position, components.MobHuntPlayer, !components.Dead); ECS_SYSTEM_TICKED(ecs, MobMeleeAtk, EcsPostUpdate, components.Position, components.Mob, components.MobHuntPlayer, components.MobMelee, !components.Dead); ECS_SYSTEM_TICKED(ecs, MobDespawnDead, EcsPostUpdate, components.Mob, components.Dead); + ECS_SYSTEM_TICKED(ecs, MobSpawner, EcsPostUpdate, components.Input, components.Position); //NOTE(DavoSK): weapons ecs_mobpos_query = ecs_query_new(world_ecs(), "components.Mob, components.Position, components.Health, components.Velocity, !components.Dead"); + ecs_pawn_query = ecs_query_new(world_ecs(), "components.Position, components.Health, components.Velocity, !components.Dead"); ECS_SYSTEM_TICKED(ecs, WeaponKnifeMechanic, EcsPostUpdate, components.WeaponKnife, components.Position, components.Input, !components.Dead); ECS_SYSTEM_TICKED(ecs, WeaponProjectileHit, EcsPostUpdate, components.WeaponProjectile, components.Position, components.Rotation); ECS_SYSTEM_TICKED(ecs, WeaponProjectileExpire, EcsPostUpdate, components.WeaponProjectile, components.Position); diff --git a/code/games/survival/src/system_mob.c b/code/games/survival/src/system_mob.c index b808bd8..994be43 100644 --- a/code/games/survival/src/system_mob.c +++ b/code/games/survival/src/system_mob.c @@ -1,3 +1,21 @@ +#define MOB_SPAWN_DELAY (uint16_t)(20*1.5f) +#define MOB_SPAWN_PERCENTAGE_FROM_MAX 0.05f +#define MOB_INITIAL_MAX 50 +#define MOB_GROWTH_FACTOR 5.0f +#define MOB_GROWTH_CONTROL 50.0f +#define MOB_SPAWN_DIST 12*WORLD_BLOCK_SIZE; +#define MOB_MAX_SPAWN_TRIES 5 + +static uint64_t max_mobs = MOB_INITIAL_MAX; +static uint64_t mob_kills = 0; +static uint16_t mob_spawn_timer = MOB_SPAWN_DELAY; +static int16_t player_spawn_counter = -1; + +void recalc_max_mobs() { + max_mobs = (uint64_t)zpl_round(MOB_INITIAL_MAX + MOB_GROWTH_FACTOR * zpl_exp((float)mob_kills / MOB_GROWTH_CONTROL)); + zpl_printf("Max mobs: %d\n", max_mobs); +} + void MobDetectPlayers(ecs_iter_t *it) { Position *p = ecs_field(it, Position, 1); @@ -27,10 +45,6 @@ void MobDetectPlayers(ecs_iter_t *it) { } } -void MobDetectPlayers1(ecs_iter_t *it) { - -} - #define MOB_MOVEMENT_SPEED 300.0f void MobMovement(ecs_iter_t *it) { @@ -93,6 +107,9 @@ void MobOnDead(ecs_iter_t *it) { v[i] = (Velocity){0.0f, 0.0f}; ecs_remove(it->world, it->entities[i], PhysicsBody); + ++mob_kills; + recalc_max_mobs(); + pkt_code_send(0, 0, (pkt_send_code){ .code = SURV_CODE_SHOW_NOTIF, .data = "mob died" @@ -114,5 +131,65 @@ void MobDespawnDead(ecs_iter_t *it) { } void MobSpawner(ecs_iter_t *it) { - + Position *pos = ecs_field(it, Position, 2); + + if (mob_spawn_timer > 0) { + TICK_VAR(mob_spawn_timer); + return; + } + + ecs_iter_t mob_it = ecs_query_iter(it->world, ecs_mobpos_query); + uint64_t curr_mobs = 0; + while (ecs_query_next(&mob_it)) { + curr_mobs += mob_it.count; + } + if (curr_mobs >= max_mobs) { + return; + } + + uint16_t mobs_to_spawn = zpl_max(1, (uint16_t)zpl_floor(MOB_SPAWN_PERCENTAGE_FROM_MAX*max_mobs)); + player_spawn_counter = (player_spawn_counter+1)%it->count; + + for (int i = player_spawn_counter; i < it->count; i++) { + const uint32_t radius = MOB_SPAWN_DIST; + uint32_t ox = (uint32_t)pos[i].x; + uint32_t oy = (uint32_t)pos[i].y; + + uint8_t tries_done = 0; + + for (;;) { + if (mobs_to_spawn == 0) { + mob_spawn_timer = MOB_SPAWN_DELAY; + return; + } + + if (tries_done == MOB_MAX_SPAWN_TRIES) { + break; + } + + float angle = get_rand_between(0, 2*ZPL_PI); + float dist = get_rand_between((float)radius, radius*1.5f); + + uint32_t cx = (uint32_t)(ox + dist * zpl_cos(angle)); + uint32_t cy = (uint32_t)(oy + dist * zpl_sin(angle)); + + if (cx >= world_dim() || cy >= world_dim() || cx <= 0 || cy <= 0) { + tries_done++; + continue; + } + + world_block_lookup l = world_block_from_realpos((float)cx, (float)cy); + uint32_t flags = blocks_get_flags(l.bid); + + if (flags & BLOCK_FLAG_COLLISION) { + tries_done++; + continue; + } + + ecs_entity_t e = entity_spawn_id(ASSET_MOB); + entity_set_position(e, (float)cx, (float)cy); + ecs_add(world_ecs(), e, MobMelee); + mobs_to_spawn--; + } + } } diff --git a/code/games/survival/src/system_weapon.c b/code/games/survival/src/system_weapon.c index f9fff01..4cf9477 100644 --- a/code/games/survival/src/system_weapon.c +++ b/code/games/survival/src/system_weapon.c @@ -8,11 +8,6 @@ ZPL_DIAGNOSTIC_POP #define WEAPON_PROJECTILE_RANGE_LIFETIME 800.0f #define WEAPON_HIT_FORCE_PUSH 400.0f -//TODO(DavoSK): move to helpers, add srand -float get_rand_between(float min, float max) { - return ((float)rand() / (float)RAND_MAX) * (max - min) + min; -} - void WeaponKnifeMechanic(ecs_iter_t* it) { WeaponKnife* weapon = ecs_field(it, WeaponKnife, 1); const Position* pos = ecs_field(it, Position, 2); @@ -31,7 +26,8 @@ void WeaponKnifeMechanic(ecs_iter_t* it) { ecs_set(it->world, e, WeaponProjectile, { .damage = weapon[i].damage, .origin_x = pos[i].x, - .origin_y = pos[i].y + .origin_y = pos[i].y, + .owner = it->entities[i] }); ecs_set(it->world, e, StreamLayerOverride, { .layer = 0 }); @@ -90,18 +86,20 @@ void WeaponProjectileHit(ecs_iter_t* it) { const Rotation* rot = ecs_field(it, Rotation, 3); for (int i = 0; i < it->count; i++) { - ecs_iter_t it2 = ecs_query_iter(it->world, ecs_mobpos_query); + ecs_iter_t it2 = ecs_query_iter(it->world, ecs_pawn_query); while (ecs_query_next(&it2)) { - Mob* mob = ecs_field(&it2, Mob, 1); - Position* mob_pos = ecs_field(&it2, Position, 2); - Health *mob_health = ecs_field(&it2, Health, 3); - Velocity *mob_velocity = ecs_field(&it2, Velocity, 4); + Position* pawn_pos = ecs_field(&it2, Position, 1); + Health *pawn_health = ecs_field(&it2, Health, 2); + Velocity *pawn_velocity = ecs_field(&it2, Velocity, 3); for (int j = 0; j < it2.count; j++) { + if (weapon[i].owner == it2.entities[j]) + continue; + float p_x = pos[i].x; float p_y = pos[i].y; - float p2_x = mob_pos[j].x /*+ v2[j].x*/; - float p2_y = mob_pos[j].y /*+ v2[j].y*/; + float p2_x = pawn_pos[j].x /*+ v2[j].x*/; + float p2_y = pawn_pos[j].y /*+ v2[j].y*/; c2AABB box_a = { .min = { p_x - WORLD_BLOCK_SIZE / 4 , p_y - WORLD_BLOCK_SIZE / 4 }, @@ -133,10 +131,10 @@ void WeaponProjectileHit(ecs_iter_t* it) { if (c2AABBtoAABB(box_a, box_b)) { float dd = zpl_sqrt(d2); - mob_health[j].dmg += weapon[i].damage; + pawn_health[j].dmg += weapon[i].damage; - mob_velocity[j].x += (dx/dd)*WEAPON_HIT_FORCE_PUSH; - mob_velocity[j].y += (dy/dd)*WEAPON_HIT_FORCE_PUSH; + pawn_velocity[j].x += (dx/dd)*WEAPON_HIT_FORCE_PUSH; + pawn_velocity[j].y += (dy/dd)*WEAPON_HIT_FORCE_PUSH; } } }