Move setup back into engine + new things
authorNiki <niki@nikiroo.be>
Thu, 17 Apr 2025 05:22:13 +0000 (07:22 +0200)
committerNiki <niki@nikiroo.be>
Thu, 17 Apr 2025 05:22:13 +0000 (07:22 +0200)
15 files changed:
src/tdef/command.h
src/tdef/enemy.c
src/tdef/enemy.h
src/tdef/engine.c
src/tdef/engine.h
src/tdef/event.c
src/tdef/event.h
src/tdef/map.c
src/tdef/reader.c
src/tdef/setup.c [deleted file]
src/tdef/setup.h [deleted file]
src/tdef/tdef.c
src/tdef/tower.c
src/tdef/wave.c
src/tdef/wave.h

index 59ee55da669d863b5efcb20255a38f207f0b8647..a18caaa2c90ed9f33624f3d8fd065855f0148e33 100644 (file)
@@ -32,10 +32,11 @@ typedef enum {
        COMMAND_TOWER,
        COMMAND_TOWER_LVL,
        COMMAND_TOWER_SP,
-       COMMAND_WAVE,
        COMMAND_ENEMY,
+       COMMAND_WAVE,
        
        COMMAND_ADD_TOWER,
+       COMMAND_ADD_ENEMY,
 
        COMMAND_QUIT,
        
index b60ee60214f5643642930446c227fd0303b34bba..9fdd2af7d64afefe26afecb8326d3c3dddf71db7 100644 (file)
@@ -22,9 +22,9 @@
 
 #include "enemy.h"
 
-enemy_t *new_enemy(int id, size_t start_tick) {
+enemy_t *new_enemy(enemy_base_t *base, int id, size_t start_tick) {
        enemy_t *self = malloc(sizeof(enemy_t));
-       if (!init_enemy(self, id, start_tick)) {
+       if (!init_enemy(self, base, id, start_tick)) {
                free(self);
                self = NULL;
        }
@@ -32,18 +32,17 @@ enemy_t *new_enemy(int id, size_t start_tick) {
        return self;
 }
 
-int init_enemy(enemy_t *self, int id, size_t start_tick) {
+int init_enemy(enemy_t *self, enemy_base_t *base, int id, size_t start_tick) {
        size_t sz = sizeof(self->CNAME);
        strncpy(self->CNAME, "[enemy        ", sz);
        self->CNAME[sz - 2] = ']';
        self->CNAME[sz - 1] = '\0';
        
        self->start_tick = start_tick;
+       self->base  = base;
        self->id    = id;
        self->hp    = 1; 
-       self->speed = 1;
        self->index = -1;
-       self->bits  = 0;
        self->alive = 0;
        
        return 1;
@@ -60,3 +59,11 @@ void uninit_enemy(enemy_t *self) {
        self->CNAME[0] = '!';
 }
 
+int init_enemy_base(enemy_base_t *self, int type, int hp, int speed, int bits){
+       self->type   = type;
+       self->max_hp = hp;
+       self->speed  = speed;
+       self->bits   = bits;
+       
+       return 1;
+}
index cb783cd769818dfadec5991e037c51491838d2d7..6c5faf45a265a096c1660d9b06f068f5b7871d54 100644 (file)
@@ -16,8 +16,8 @@
 
 typedef struct {
        int type; // identify the unique enemy type
+       int max_hp;
        int speed; // paths per tick
-       int index; // index in paths
        int bits; // on death
 } enemy_base_t;
 
@@ -28,21 +28,19 @@ typedef struct {
  */
 typedef struct {
        char CNAME[10];
+       enemy_base_t *base;
        size_t start_tick;
+       int index; // index in paths
        int id;    // unique per wave
        int hp;
        
-       // should move to enemy_base_t
-       int speed; // paths per tick
-       int index; // index in paths
-       int bits; // on death
-       
        int alive;
 } enemy_t;
 
 /**
  * Create a new enemy.
  * 
+ * @param base the type of enemy (will NOT be free'd by this object)
  * @param id the unique number (per wave) of this enemy
  * @param start_tick the tick at which the enemy will start on the map
  *
@@ -53,15 +51,16 @@ typedef struct {
  *
  * @return a new enemy (you must later call `free_enemy()`)
  */
-enemy_t *new_enemy(int id, size_t start_tick);
+enemy_t *new_enemy(enemy_base_t *base, int id, size_t start_tick);
 
 /**
  * Initialise a new enemy.
  * 
+ * @param base the type of enemy (will NOT be free'd by this object)
  * @param id the unique number (per wave) of this enemy
  * @param start_tick the tick at which the enemy will start on the map
  */
-int init_enemy(enemy_t *self, int id, size_t start_tick);
+int init_enemy(enemy_t *self, enemy_base_t *base, int id, size_t start_tick);
 
 /** 
  * Free the resources held for the given enemy: you must not use it any more.
@@ -84,4 +83,6 @@ void free_enemy(enemy_t *self);
  */
 void uninit_enemy(enemy_t *self);
 
+int init_enemy_base(enemy_base_t *self, int type, int hp, int speed, int bits);
+
 #endif /* ENEMY_H */
index 3bf1a7fc7740916526d97f98cddd0c88269576ea..447d63d0ba9cffae7183b406b9c5d7d6d5426685 100644 (file)
@@ -152,8 +152,14 @@ int engine_add_tower(engine_t *self, int type, int x, int y) {
                return 0;
        
        tower_base_t *base = engine_get_tower_base(self, type);
-       if (!base)
+       if (!base) {
+               event_t event;
+               init_event(&event, EVENT_ERROR);
+               event.error = EEVENT_UNKNOWN_TYPE;
+               array_push(self->events, &event);
+
                return 0;
+       }
        
        if (self->bits < base->cost) {
                event_t event;
@@ -188,3 +194,93 @@ tower_base_t *engine_get_tower_base(engine_t *self, int type) {
        return NULL;
 }
 
+enemy_base_t *engine_get_enemy_base(engine_t *self, int type) {
+       array_loop (self->ebases, base, enemy_base_t) {
+               if (base->type == type)
+                       return base;
+       }
+       
+       return NULL;
+}
+
+tower_base_t *setup_tower_base(engine_t *self, int type, int cost) {
+       tower_base_t *base = engine_get_tower_base(self, type);
+       if (base) { // already configured
+               event_t event;
+               init_event(&event, EVENT_ERROR);
+               event.error = EEVENT_ALREADY_CONFIGURED;
+               array_push(self->events, &event);
+               
+               return NULL;
+       }
+       
+       base = array_new(self->tbases);
+       init_tower_base(base, type);
+       base->cost = cost;
+       
+       return base;
+}
+
+int setup_wave(engine_t *self, int start_tick, int bits) {
+       wave_t *wave = array_new(self->waves);
+       if (!wave)
+               return 0;
+       
+       init_wave(wave, start_tick);
+       wave->bits = bits;
+       
+       return 1;
+}
+
+enemy_base_t *setup_enemy_base(
+               engine_t *self, int type, int hp, int speed, int bits) {
+       enemy_base_t *base = engine_get_enemy_base(self, type);
+       if (base) { // already configured
+               event_t event;
+               init_event(&event, EVENT_ERROR);
+               event.error = EEVENT_ALREADY_CONFIGURED;
+               array_push(self->events, &event);
+               
+               return NULL;
+       }
+       
+       base = array_new(self->ebases);
+       init_enemy_base(base, type, hp, speed, bits);
+       
+       return base;
+}
+
+enemy_t *setup_enemy(engine_t *self, int type, int id, size_t start_tick) {
+       if (!self->waves->count)
+               if (!setup_wave(self, 0, 0))
+                       return 0;
+       
+       //TODO: id must be unique (total, not only per wave)
+       
+       enemy_base_t *base = engine_get_enemy_base(self, type);
+       if (!base) {
+               event_t event;
+               init_event(&event, EVENT_ERROR);
+               event.error = EEVENT_UNKNOWN_TYPE;
+               array_push(self->events, &event);
+
+               return 0;
+       }
+       
+       wave_t *wave = array_last(self->waves);
+       return wave_add_enemy(wave, base, id, start_tick);
+}
+
+int setup_path(engine_t *self, int x, int y) {
+       if (!self->map) {
+               event_t event;
+               init_event(&event, EVENT_ERROR);
+               event.error = EEVENT_MAP_NOT_INITIALISED;
+               array_push(self->events, &event);
+
+               return 0;
+       }
+       
+       return map_add_path(self->map, x, y);
+}
+
index 15642f093c1d0dcccaa6561b56091d13c6626caa..42814893779154abb9d98ccecb524e79bb811e9b 100644 (file)
@@ -86,5 +86,20 @@ int engine_add_tower(engine_t *self, int type, int x, int y);
 
 tower_base_t *engine_get_tower_base(engine_t *self, int type);
 
+enemy_base_t *engine_get_enemy_base(engine_t *self, int type);
+
+// Setup:
+
+tower_base_t *setup_tower_base(engine_t *self, int type, int cost);
+
+int setup_wave(engine_t *self, int start_tick, int bits);
+
+enemy_base_t *setup_enemy_base(
+               engine_t *self, int type, int hp, int speed, int bits);
+
+enemy_t *setup_enemy(engine_t *self, int type, int id, size_t start_tick);
+
+int setup_path(engine_t *self, int x, int y);
+
 #endif /* ENGINE_H */
 
index 896e605fd1447505401e4a609e0670e452a6d291..a3a08a01657577558e89f8a6f0c181320ae18c4c 100644 (file)
@@ -81,6 +81,7 @@ const char *event_ename(event_t *self) {
        switch(self->x) {
        case EEVENT_SUCCESS             : return "SUCCESS"            ;
        case EEVENT_MAP_NOT_INITIALISED : return "MAP_NOT_INITIALISED";
+       case EEVENT_UNKNOWN_TYPE        : return "UNKNOWN_TYPE"       ;
        case EEVENT_ALREADY_CONFIGURED  : return "ALREADY_CONFIGURED" ;
        case EEVENT_NOT_ENOUGH_BITS     : return "NOT_ENOUGH_BITS"    ;
        }
index 71b88bb6da770355ab3878960d612af728d46930..76a189fb7fd6a4abe5fc35e13af002594d8076d2 100644 (file)
@@ -38,6 +38,7 @@ typedef enum {
 typedef enum {
        EEVENT_SUCCESS,
        EEVENT_MAP_NOT_INITIALISED,
+       EEVENT_UNKNOWN_TYPE,
        EEVENT_ALREADY_CONFIGURED,
        EEVENT_NOT_ENOUGH_BITS,
 } eevent_type;
index fa385b6ddda401acbe44db0b36d5ffbbc64eff5f..2b8a46015332109bad3b8affbf6d50c2d5208038 100644 (file)
@@ -199,7 +199,7 @@ int map_hit_1(map_t *self, int current_tick, array_t *events) {
 
 void move(map_t *self, enemy_t *enemy, array_t *events, int reverse) {
        int source = enemy->index;
-       int target = source >= 0 ? source+1 : 0;
+       int target = source >= 0 ? (source + enemy->base->speed) : 0;
        event_t event;
        init_event(&event, EVENT_MOVE);
        
@@ -258,7 +258,7 @@ int hit(map_t *self, proj_t *proj, array_t *events) {
                        e->alive = 0;
                        path->enemy = NULL;
                        init_event(&event, EVENT_DIE);
-                       bits = e->bits;
+                       bits = e->base->bits;
                        event.move_to_x = bits;
                } else {
                        init_event(&event, EVENT_HIT);
index a6e0bdb804d0182dd86f51ca79e57ecdde9fc50c..0bc324b39a46dfcc29dfdf07892ce2f4bb133604 100644 (file)
 //   > (0) type      : the unique identifier for this tower type
 //   > (1) super_cost
 //   > (2) super_power
+// * enemy    : will setup a new enemy type
+//   > (0) type      : the unique identifier for this enemy type
+//   > (1) hp        : life/hit points the enemy can take
+//   > (2) speed     : speed in paths per tick
+//   > (3) bits      : how much bits received on enemy death
 // * wave            : configure a new wave TODO
-// * enemy : add a new enemy in the current wave (can create the first one)
-//   > type          : the enemy type
-//   > id            : the *unique* id of this enemy
-//   > start_tick    : the tick at which it will appear (wave-relative)
 //
-// Runtime commands:
+// Add commands:
 // * add_tower: add a new tower on the map (will cost bits)
 //   > (0) type      : the type of tower to add
 //   > (1) X position: the X coordinate
 //   > (2) Y position: the Y coordinate
+// * add_enemy : add a new enemy in the current wave (can create the first one)
+//   > type          : the enemy type
+//   > id            : the *unique* id of this enemy
+//   > start_tick    : the tick at which it will appear (wave-relative)
 //
 // Other commands:
 // * display  : will toggle display (debug) mode
@@ -142,12 +147,16 @@ command_t *reader_readnext(FILE *file) {
                                cmd->type = COMMAND_INVALID;
                        if (command_read_count(cmd, line->string) > 2)
                                cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string) != 1)
+                               cmd->type = COMMAND_INVALID;
                } else if (is_cmd(line, "bits")) {
                        cmd->type = COMMAND_BITS;
                        if (!command_read_int(cmd, line->string, 0, 0))
                                cmd->type = COMMAND_INVALID;
                        if (command_read_count(cmd, line->string) > 2)
                                cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string) != 1)
+                               cmd->type = COMMAND_INVALID;
                } else if (is_cmd(line, "path")) {
                        cmd->type = COMMAND_PATH;
                        if (!command_read_int(cmd, line->string, 0, -1))
@@ -158,28 +167,44 @@ command_t *reader_readnext(FILE *file) {
                        cmd->type = COMMAND_TOWER;
                        if (!command_read_int(cmd, line->string, 0, 1))
                                cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string) != 2)
+                               cmd->type = COMMAND_INVALID;
                } else if (is_cmd(line, "tower_lvl")) {
                        cmd->type = COMMAND_TOWER_LVL;
                        if (!command_read_int(cmd, line->string, 0, 4))
                                cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string) != 5)
+                               cmd->type = COMMAND_INVALID;
                } else if (is_cmd(line, "tower_sp")) {
                        cmd->type = COMMAND_TOWER_SP;
                        // TODO
-               } else if (is_cmd(line, "wave")) {
-                       cmd->type = COMMAND_WAVE;
-                       // TODO
                } else if (is_cmd(line, "enemy")) {
                        cmd->type = COMMAND_ENEMY;
-                       if (!command_read_int(cmd, line->string, 0, 2))
+                       if (!command_read_int(cmd, line->string, 0, 3))
+                               cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string) != 4)
                                cmd->type = COMMAND_INVALID;
+               } else if (is_cmd(line, "wave")) {
+                       cmd->type = COMMAND_WAVE;
+                       // TODO
                } else if (is_cmd(line, "add_tower")) {
                        cmd->type = COMMAND_ADD_TOWER;
                        if (!command_read_int(cmd, line->string, 0, 2))
                                cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string) != 3)
+                               cmd->type = COMMAND_INVALID;
+               } else if (is_cmd(line, "add_enemy")) {
+                       cmd->type = COMMAND_ADD_ENEMY;
+                       if (!command_read_int(cmd, line->string, 0, 2))
+                               cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string) != 3)
+                               cmd->type = COMMAND_INVALID;
                } else if (is_cmd(line, "quit")) {
                        cmd->type = COMMAND_QUIT;
                        if (command_read_count(cmd, line->string))
                                cmd->type = COMMAND_INVALID;
+                       if (command_read_count(cmd, line->string))
+                               cmd->type = COMMAND_INVALID;
                }
        }
        
diff --git a/src/tdef/setup.c b/src/tdef/setup.c
deleted file mode 100644 (file)
index 19426c6..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * TDef: small tower defense game
- *
- * Copyright (C) 2025 Niki Roo
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "setup.h"
-#include "event.h"
-
-tower_base_t *setup_tower_base(engine_t *self, int type, int cost) {
-       tower_base_t *base = engine_get_tower_base(self, type);
-       if (base) { // already configured
-               event_t event;
-               init_event(&event, EVENT_ERROR);
-               event.error = EEVENT_ALREADY_CONFIGURED;
-               array_push(self->events, &event);
-               
-               return NULL;
-       }
-       
-       base = array_new(self->tbases);
-       init_tower_base(base, type);
-       base->cost = cost;
-       
-       return base;
-}
-
-int setup_wave(engine_t *self, int start_tick, int bits) {
-       wave_t *wave = array_new(self->waves);
-       if (!wave)
-               return 0;
-       
-       init_wave(wave, start_tick);
-       wave->bits = bits;
-       
-       return 1;
-}
-
-enemy_t *setup_enemy(engine_t *self, int type, int id, size_t start_tick) {
-       if (!self->waves->count)
-               if (!setup_wave(self, 0, 0))
-                       return 0;
-       
-       //TODO: type and enemy_base_t
-       //TODO: id must be unique (total, not only per wave)
-       
-       wave_t *wave = array_last(self->waves);
-       return wave_add_enemy(wave, id, start_tick);
-}
-
-int setup_path(engine_t *self, int x, int y) {
-       if (!self->map) {
-               event_t event;
-               init_event(&event, EVENT_ERROR);
-               event.error = EEVENT_MAP_NOT_INITIALISED;
-               array_push(self->events, &event);
-
-               return 0;
-       }
-       
-       return map_add_path(self->map, x, y);
-}
-
diff --git a/src/tdef/setup.h b/src/tdef/setup.h
deleted file mode 100644 (file)
index fc74b98..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/** 
- * @file setup.h
- * @author Niki
- * @date 2025
- * 
- * @brief bla
- *
- * blablabla
- *
- */
-
-#ifndef SETUP_H
-#define SETUP_H
-
-#include "engine.h"
-
-tower_base_t *setup_tower_base(engine_t *self, int type, int cost);
-
-int setup_wave(engine_t *self, int start_tick, int bits);
-
-enemy_t *setup_enemy(engine_t *self, int type, int id, size_t start_tick);
-
-int setup_path(engine_t *self, int x, int y);
-
-#endif /* SETUP_H */
index ebf11950286aabd46f1df8060c3c28bce9fcf9e7..13227e760e255e3c1431410e5de9d2d81b7b5b2e 100644 (file)
@@ -27,7 +27,6 @@
 #include "reader.h"
 #include "event.h"
 #include "command.h"
-#include "setup.h"
 
 int displayMode = 0;
 
@@ -137,24 +136,29 @@ int process_cmd(command_t *cmd, engine_t *engine) {
                // TODO
                printf("TODO: command_tower_sp\n");
                break;
+       case COMMAND_ENEMY:
+               setup_enemy_base(
+                       engine,
+                       command_get_int(cmd, 0),
+                       command_get_int(cmd, 1),
+                       command_get_int(cmd, 2),
+                       command_get_int(cmd, 3)
+               );
+               break;
        case COMMAND_WAVE:
                // TODO
                printf("TODO: command_wave\n");
                break;
-       case COMMAND_ENEMY:
-               ;enemy_t *enemy = setup_enemy(
+       case COMMAND_ADD_TOWER:
+               engine_add_tower(
                        engine,
                        command_get_int(cmd, 0),
                        command_get_int(cmd, 1),
                        command_get_int(cmd, 2)
                );
-               // TODO: enemy_base:
-               enemy->speed = 2;
-               enemy->bits = 5;
-               // end-of-TODO
                break;
-       case COMMAND_ADD_TOWER:
-               engine_add_tower(
+       case COMMAND_ADD_ENEMY:
+               setup_enemy(
                        engine,
                        command_get_int(cmd, 0),
                        command_get_int(cmd, 1),
index dc0956b0d8270154a9f08431861da2957e913efd..6eabe089a19cba172005844b320d090dbb8ebc98 100644 (file)
@@ -93,9 +93,12 @@ proj_t *tower_fire(tower_t *self, int current_tick, array_t *enemies,
        
        // If not found: return NULL;
 
+       int attack = self->base->stats[self->lvl_attack].attack;
+       int speed = self->base->stats[self->lvl_speed].speed;
+       
        proj_t *proj = new_proj(3, 0); // TODO
        proj->desc = self->projectile;
-       proj->desc.damage = 10; // TODO
+       proj->desc.damage = attack;
        proj->boom_tick = current_tick + 3; // TODO: compute from speed
        
        self->fire_delayed = self->base->stats[self->lvl_speed].attack;
index 9f12a2d6fe3a84e70a00f8d926fd409345a67a44..0272dff9e988733d04d58fafa80f950b743597ce 100644 (file)
@@ -69,11 +69,12 @@ void uninit_wave(wave_t *self) {
        self->last_enemy = NULL;
 }
 
-enemy_t *wave_add_enemy(wave_t *self, int id, size_t start_tick) {
+enemy_t *wave_add_enemy(
+               wave_t *self, enemy_base_t *base, int id, size_t start_tick) {
        enemy_t *enemy = array_new(self->enemies);
        if (!enemy)
                return NULL;
-       init_enemy(enemy, id, start_tick);
+       init_enemy(enemy, base, id, start_tick);
        return enemy;
 }
 
index 58b7cfac9230083d0ac85e51a1baceb0b9a5c780..81ead921e258d113640f596c82706d21bf2e16cf 100644 (file)
@@ -73,7 +73,8 @@ void free_wave(wave_t *self);
  */
 void uninit_wave(wave_t *self);
 
-enemy_t *wave_add_enemy(wave_t *self, int id, size_t start_tick);
+enemy_t *wave_add_enemy(
+               wave_t *self, enemy_base_t *base, int id, size_t start_tick);
 
 enemy_t *wave_next_enemy(wave_t *self, int tick);