2022-07-31 14:34:47 +00:00
|
|
|
#include <math.h>
|
|
|
|
|
2021-11-01 18:55:13 +00:00
|
|
|
void DemoNPCMoveAround(ecs_iter_t *it) {
|
2022-07-31 14:34:47 +00:00
|
|
|
Velocity *v = ecs_field(it, Velocity, 1);
|
2021-11-01 18:55:13 +00:00
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
float d = zpl_quake_rsqrt(v[i].x*v[i].x + v[i].y*v[i].y);
|
2022-09-28 05:29:32 +00:00
|
|
|
v[i].x += (v[i].x*d*game_rules.demo_npc_move_speed*safe_dt(it) + zpl_cos(zpl_to_radians((float)(rand()%360)))*game_rules.demo_npc_steer_speed*safe_dt(it));
|
|
|
|
v[i].y += (v[i].y*d*game_rules.demo_npc_move_speed*safe_dt(it) + zpl_sin(zpl_to_radians((float)(rand()%360)))*game_rules.demo_npc_steer_speed*safe_dt(it));
|
|
|
|
|
2022-08-08 11:19:12 +00:00
|
|
|
entity_wake(it->entities[i]);
|
2021-11-01 18:55:13 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-23 10:51:12 +00:00
|
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#define CREATURE_FOOD_SATISFY_FOR 200
|
|
|
|
#define CREATURE_MATING_SATISFY_FOR 300
|
|
|
|
#define CREATURE_INTERACT_RANGE 5625.0f
|
|
|
|
#define CREATURE_SEEK_FOOD_MOVEMENT_SPEED 0.98f
|
|
|
|
#define CREATURE_SEEK_MATE_MOVEMENT_SPEED 0.357f
|
|
|
|
#define CREATURE_SEEK_ROAM_MOVEMENT_SPEED 50.0f // *dt
|
|
|
|
|
|
|
|
void CreatureCheckNeeds(ecs_iter_t *it) {
|
|
|
|
Creature *c = ecs_field(it, Creature, 1);
|
|
|
|
|
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
// check hunger
|
|
|
|
if (c[i].hunger_satisfied < 1) {
|
|
|
|
ecs_add(it->world, it->entities[i], SeeksFood);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check mating
|
|
|
|
if (c[i].mating_satisfied < 1) {
|
|
|
|
ecs_add(it->world, it->entities[i], SeeksCompanion);
|
|
|
|
}
|
|
|
|
|
|
|
|
// die of an old age
|
|
|
|
if (c[i].life_remaining < 1) {
|
|
|
|
entity_despawn(it->entities[i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// tick down needs
|
|
|
|
TICK_VAR(c[i].hunger_satisfied);
|
|
|
|
TICK_VAR(c[i].mating_satisfied);
|
|
|
|
TICK_VAR(c[i].life_remaining);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreatureSeekFood(ecs_iter_t *it) {
|
|
|
|
Creature *c = ecs_field(it, Creature, 1);
|
|
|
|
Position *p = ecs_field(it, Position, 2);
|
|
|
|
Velocity *v = ecs_field(it, Velocity, 3);
|
|
|
|
|
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
size_t ents_count;
|
|
|
|
uint64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2);
|
|
|
|
|
|
|
|
float closest_ent_dist = ZPL_F32_MAX;
|
|
|
|
uint64_t closest_ent = 0;
|
|
|
|
Position *p2 = 0;
|
|
|
|
|
|
|
|
// find the closest item of kind ASSET_CREATURE_FOOD
|
|
|
|
for (size_t j = 0; j < ents_count; j++) {
|
|
|
|
Item *drop = 0;
|
|
|
|
uint64_t ent_id = ents[j];
|
|
|
|
if ((drop = ecs_get_mut_if_ex(it->world, ent_id, Item))) {
|
|
|
|
if (drop->kind != ASSET_CREATURE_FOOD)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
p2 = ecs_get_mut_ex(it->world, ent_id, Position);
|
|
|
|
float dx = p2->x - p[i].x;
|
|
|
|
float dy = p2->y - p[i].y;
|
|
|
|
float range = (dx*dx + dy*dy);
|
|
|
|
|
|
|
|
// item is close enough, eat it!
|
|
|
|
if (range < CREATURE_INTERACT_RANGE) {
|
|
|
|
drop->quantity--;
|
|
|
|
|
|
|
|
if (drop->quantity == 0)
|
|
|
|
item_despawn(ent_id);
|
|
|
|
|
|
|
|
c[i].hunger_satisfied = CREATURE_FOOD_SATISFY_FOR;
|
|
|
|
ecs_remove(it->world, it->entities[i], SeeksFood);
|
|
|
|
}
|
|
|
|
else if (range < closest_ent_dist)
|
|
|
|
closest_ent = ent_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// drift towards the item
|
|
|
|
if (closest_ent) {
|
|
|
|
float dx = p2->x - p[i].x;
|
|
|
|
float dy = p2->y - p[i].y;
|
|
|
|
float r = 1; //zpl_sqrt(dx*dx + dy*dy);
|
|
|
|
v[i].x = (dx/r) * CREATURE_SEEK_MATE_MOVEMENT_SPEED;
|
|
|
|
v[i].y = (dy/r) * CREATURE_SEEK_MATE_MOVEMENT_SPEED;
|
|
|
|
} else {
|
|
|
|
// die if no food is left
|
|
|
|
entity_despawn(it->entities[i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreatureSeekCompanion(ecs_iter_t *it) {
|
|
|
|
Creature *c = ecs_field(it, Creature, 1);
|
|
|
|
Position *p = ecs_field(it, Position, 2);
|
|
|
|
Velocity *v = ecs_field(it, Velocity, 3);
|
|
|
|
|
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
size_t ents_count;
|
|
|
|
uint64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2);
|
|
|
|
|
|
|
|
float closest_ent_dist = ZPL_F32_MAX;
|
|
|
|
uint64_t closest_ent = 0;
|
|
|
|
Position *p2 = 0;
|
|
|
|
|
|
|
|
// find the closest entity that also seeks a companion
|
|
|
|
for (size_t j = 0; j < ents_count; j++) {
|
|
|
|
uint64_t ent_id = ents[j];
|
|
|
|
if (ent_id != it->entities[i] && ecs_get_if(it->world, ent_id, SeeksCompanion)) {
|
|
|
|
p2 = ecs_get_mut_ex(it->world, ent_id, Position);
|
|
|
|
float dx = p2->x - p[i].x;
|
|
|
|
float dy = p2->y - p[i].y;
|
|
|
|
float range = (dx*dx + dy*dy);
|
|
|
|
|
|
|
|
// creature is close enough, mate them!
|
|
|
|
if (range < CREATURE_INTERACT_RANGE) {
|
|
|
|
// remove the need
|
|
|
|
c[i].mating_satisfied = CREATURE_MATING_SATISFY_FOR;
|
|
|
|
ecs_remove(it->world, it->entities[i], SeeksCompanion);
|
|
|
|
ecs_remove(it->world, ent_id, SeeksCompanion);
|
|
|
|
|
|
|
|
// spawn a new creature
|
|
|
|
uint64_t ch = entity_spawn_id(ASSET_CREATURE);
|
|
|
|
entity_set_position(ch, p[i].x, p[i].y);
|
|
|
|
}
|
|
|
|
else if (range < closest_ent_dist)
|
|
|
|
closest_ent = ent_id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// drift towards the creature
|
|
|
|
if (closest_ent) {
|
|
|
|
float dx = p2->x - p[i].x;
|
|
|
|
float dy = p2->y - p[i].y;
|
|
|
|
float r = 1; //zpl_sqrt(dx*dx + dy*dy);
|
|
|
|
v[i].x = (dx/r) * CREATURE_SEEK_MATE_MOVEMENT_SPEED;
|
|
|
|
v[i].y = (dy/r) * CREATURE_SEEK_MATE_MOVEMENT_SPEED;
|
|
|
|
entity_wake(it->entities[i]);
|
|
|
|
} else {
|
|
|
|
// no companion is found, let's try again later.
|
|
|
|
c[i].mating_satisfied = CREATURE_MATING_SATISFY_FOR;
|
|
|
|
ecs_remove(it->world, it->entities[i], SeeksCompanion);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CreatureRoamAround(ecs_iter_t *it) {
|
|
|
|
Velocity *v = ecs_field(it, Velocity, 1);
|
|
|
|
for (int i = 0; i < it->count; i++) {
|
|
|
|
float d = zpl_quake_rsqrt(v[i].x*v[i].x + v[i].y*v[i].y);
|
|
|
|
if (zpl_abs(v[i].x) < 0.1f)
|
|
|
|
v[i].x = (float)(rand() % 5);
|
|
|
|
if (zpl_abs(v[i].y) < 0.1f)
|
|
|
|
v[i].y = (float)(rand() % 5);
|
|
|
|
v[i].x += (v[i].x*d*CREATURE_SEEK_ROAM_MOVEMENT_SPEED*safe_dt(it) + zpl_cos(zpl_to_radians((float)(rand()%360)))*game_rules.demo_npc_steer_speed*safe_dt(it));
|
|
|
|
v[i].y += (v[i].y*d*CREATURE_SEEK_ROAM_MOVEMENT_SPEED*safe_dt(it) + zpl_sin(zpl_to_radians((float)(rand()%360)))*game_rules.demo_npc_steer_speed*safe_dt(it));
|
|
|
|
|
|
|
|
entity_wake(it->entities[i]);
|
|
|
|
}
|
|
|
|
}
|