tower: select target wip
authorNiki <niki@nikiroo.be>
Thu, 17 Apr 2025 15:16:57 +0000 (17:16 +0200)
committerNiki <niki@nikiroo.be>
Thu, 17 Apr 2025 15:16:57 +0000 (17:16 +0200)
src/tdef/tower.c

index 6eabe089a19cba172005844b320d090dbb8ebc98..68ffd57bde229df6005f2c684d7fa34de2904433 100644 (file)
 #include <stdlib.h>
 
 #include "tower.h"
+#include "path.h"
+
+array_t *enemies_in_range(tower_t *self, array_t *enemies);
+array_t *paths_in_range(tower_t *self, array_t *paths);
+int at_p_in(int x, int y, path_t *path, int speed);
+path_t *get_target(tower_t *self, array_t *enemies, array_t *paths);
 
 tower_t *new_tower(tower_base_t *base, int x, int y) {
        tower_t *self = malloc(sizeof(tower_t));
@@ -80,29 +86,109 @@ void tower_rearm(tower_t *self) {
 }
 
 proj_t *tower_fire(tower_t *self, int current_tick, array_t *enemies, 
-               array_t *path) {
+               array_t *paths) {
        
        if (self->fire_delayed > 0)
                return NULL;
 
-       // TODO:
-       // select target (3 modes)
-       // check target expected position
-       // fire at position if <= range
-       // (skip to next if not)
-       
-       // If not found: return NULL;
+       path_t *target = get_target(self, enemies, paths);
+       if (!target)
+               return NULL;
 
        int attack = self->base->stats[self->lvl_attack].attack;
-       int speed = self->base->stats[self->lvl_speed].speed;
+       int speed  = self->base->stats[self->lvl_speed ].speed;
+       int range  = self->base->stats[self->lvl_range ].range;
        
-       proj_t *proj = new_proj(3, 0); // TODO
+       proj_t *proj = new_proj(target->x, target->y);
        proj->desc = self->projectile;
        proj->desc.damage = attack;
        proj->boom_tick = current_tick + 3; // TODO: compute from speed
        
-       self->fire_delayed = self->base->stats[self->lvl_speed].attack;
+       self->fire_delayed = speed;
        
        return proj;
 }
 
+array_t *enemies_in_range(tower_t *self, array_t *enemies) {
+       array_t *in_range = new_array(sizeof(enemy_t*), enemies->count/2+1);
+       
+       return in_range;
+}
+
+array_t *paths_in_range(tower_t *self, array_t *paths) {
+       array_t *in_range = new_array(sizeof(path_t *), paths->count/2+1);
+       
+       return in_range;
+}
+
+int at_p_in(int x, int y, path_t *path, int speed) {
+       // TODO
+       return 1;
+}
+
+path_t *get_target(tower_t *self, array_t *enemies, array_t *paths) {
+       enemy_t *e_target = NULL;
+       path_t *p_target = NULL;
+       
+       // TODO: move to configurable
+       #define TARGET_FIRST 0
+       #define TARGET_LAST 1
+       #define TARGET_WEAKER 2
+       #define TARGET_STRONGER 3
+       int mode = TARGET_FIRST;
+       
+       
+       // TODO: move paths_in_range as a member of tower_t, cache it
+       array_t *e_in_range = enemies_in_range(self, enemies);
+       array_t *p_in_range = (e_in_range->count) ? 
+               paths_in_range(self, paths)
+               : new_array(sizeof(enemy_t*), 0);
+       
+       if (e_in_range->count && p_in_range->count)
+       array_loop (p_in_range, pptr, path_t*) {
+               path_t *p = *pptr;
+               int proj_at_p_in = at_p_in(
+                       self->x, self->y, p, self->proj_speed
+               );
+               
+               array_loop (e_in_range, eptr, enemy_t*) {
+                       enemy_t *e = *eptr;
+                       path_t *e_p = (path_t*)array_get(paths, e->index);
+                       int enemy_at_p_in = at_p_in(
+                               e_p->x, e_p->y, p, e->base->speed
+                       );
+                       
+                       if (proj_at_p_in == enemy_at_p_in) {
+                               int take_it = 0;
+                               switch(mode) {
+                               case TARGET_FIRST:
+                                       if (!e_target)
+                                               take_it = 1;
+                               break;
+                               case TARGET_LAST:
+                                       take_it = 1;
+                               break;
+                               case TARGET_WEAKER:
+                                       if (!e_target || e->hp < e_target->hp)
+                                               take_it = 1;
+                               break;
+                               case TARGET_STRONGER:
+                                       if (!e_target || e->hp > e_target->hp)
+                                               take_it = 1;
+                               break;
+                               }
+                               
+                               if (take_it) {
+                                       e_target = e;
+                                       p_target = p;
+                               }
+                       }
+               }
+       }
+       
+       free_array(p_in_range);
+       free_array(e_in_range);
+       
+       return p_target;
+}
+