mob spawner + friendly fire
parent
d864661e65
commit
213710e922
|
@ -260,6 +260,7 @@ typedef struct {
|
|||
typedef struct {
|
||||
uint8_t damage;
|
||||
float origin_x, origin_y;
|
||||
ecs_entity_t owner;
|
||||
} WeaponProjectile;
|
||||
|
||||
#define _COMPS\
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue