From bafac3b91dd52fac76d6d096c7b4b4340dad2351 Mon Sep 17 00:00:00 2001 From: Niki Roo Date: Tue, 8 Apr 2025 22:32:55 +0200 Subject: [PATCH] new wave system --- src/tdef/enemy.c | 7 +-- src/tdef/enemy.h | 7 ++- src/tdef/engine.c | 70 ++++++++++++++++++++---------- src/tdef/engine.h | 8 +++- src/tdef/event.c | 1 + src/tdef/event.h | 1 + src/tdef/map.c | 5 ++- src/tdef/tdef.c | 11 +++-- src/tdef/wave.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++ src/tdef/wave.h | 80 ++++++++++++++++++++++++++++++++++ 10 files changed, 261 insertions(+), 35 deletions(-) create mode 100644 src/tdef/wave.c create mode 100644 src/tdef/wave.h diff --git a/src/tdef/enemy.c b/src/tdef/enemy.c index 1918bb8..b2940ed 100644 --- a/src/tdef/enemy.c +++ b/src/tdef/enemy.c @@ -22,9 +22,9 @@ #include "enemy.h" -enemy_t *new_enemy(size_t start_tick) { +enemy_t *new_enemy(int id, size_t start_tick) { enemy_t *self = malloc(sizeof(enemy_t)); - if (!init_enemy(self, start_tick)) { + if (!init_enemy(self, id, start_tick)) { free(self); self = NULL; } @@ -32,13 +32,14 @@ enemy_t *new_enemy(size_t start_tick) { return self; } -int init_enemy(enemy_t *self, size_t start_tick) { +int init_enemy(enemy_t *self, 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->id = id; self->hp = 1; self->speed = 1; self->index = -1; diff --git a/src/tdef/enemy.h b/src/tdef/enemy.h index ee91c2a..3f19626 100644 --- a/src/tdef/enemy.h +++ b/src/tdef/enemy.h @@ -22,6 +22,7 @@ typedef struct { char CNAME[10]; size_t start_tick; + int id; // unique per wave int hp; int speed; // paths per tick int index; // index in paths @@ -31,6 +32,7 @@ typedef struct { /** * Create a new enemy. * + * @param id the unique number (per wave) of this enemy * @param start_tick the tick at which the enemy will start on the map * * @note always identical to malloc + init_enemy @@ -40,14 +42,15 @@ typedef struct { * * @return a new enemy (you must later call `free_enemy()`) */ -enemy_t *new_enemy(size_t start_tick); +enemy_t *new_enemy(int id, size_t start_tick); /** * Initialise a new enemy. * + * @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, size_t start_tick); +int init_enemy(enemy_t *self, int id, size_t start_tick); /** * Free the resources held for the given enemy: you must not use it any more. diff --git a/src/tdef/engine.c b/src/tdef/engine.c index b965d81..91cd5c8 100644 --- a/src/tdef/engine.c +++ b/src/tdef/engine.c @@ -23,6 +23,8 @@ #include "engine.h" #include "event.h" +int tickit(); + engine_t *new_engine(map_t *map) { engine_t *self = malloc(sizeof(engine_t)); if (!init_engine(self, map)) { @@ -41,12 +43,12 @@ int init_engine(engine_t *self, map_t *map) { self->map = map; self->current_tick = 0; - self->enemies = new_array(sizeof(enemy_t), 100); - self->events = new_array(sizeof(event_t), 20); - self->last_enemy = NULL; + self->waves = new_array(sizeof(wave_t) , 10); + self->events = new_array(sizeof(event_t), 20); + self->current_wave = -1; self->life = 10; - if (!self->enemies || !self->events) { + if (!self->waves || !self->events) { uninit_engine(self); return 0; } @@ -64,31 +66,42 @@ void free_engine(engine_t *self) { void uninit_engine(engine_t *self) { self->CNAME[0] = '!'; - if (self->enemies) { - array_loop(self->enemies, enemy, enemy_t) { - uninit_enemy(enemy); + if (self->waves) { + array_loop(self->waves, wave, wave_t) { + uninit_wave(wave); } } - free_map(self->map) ; self->map = NULL; - free_array(self->events) ; self->events = NULL; - free_array(self->enemies); self->enemies = NULL; + free_map(self->map) ; self->map = NULL; + free_array(self->events) ; self->events = NULL; + free_array(self->waves) ; self->waves = NULL; } void engine_tick(engine_t *self) { array_clear(self->events); - enemy_t *enemy; - if (!self->last_enemy) - enemy = array_first(self->enemies); - else - enemy = array_next(self->enemies, self->last_enemy); - // Note that multiple ennemies per tick will trigger the backfill - while (enemy && enemy->start_tick >= self->current_tick) { - self->last_enemy = enemy; - map_enemy_enters(self->map, enemy, self->events); - enemy = array_next(self->enemies, enemy); + array_loop_i (self->waves, wave, wave_t, i) { + if (wave->done) + continue; + + enemy_t *enemy = wave_next_enemy(wave, self->current_tick); + + int cw = self->current_wave; + if (enemy && (cw < 0 || cw < i)) { + self->current_wave = i; + event_t event; + init_event(&event, WAVE); + event.x = i, + array_push(self->events, &event); + } + + while (enemy) { + map_enemy_enters(self->map, enemy, self->events); + + enemy = wave_next_enemy(wave, self->current_tick); + } + } map_move_1(self->map, self->events); @@ -98,10 +111,23 @@ void engine_tick(engine_t *self) { self->current_tick++; } -int setup_enemy(engine_t *self, enemy_t *enemy) { - if (!array_push(self->enemies, enemy)) +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; } +int setup_enemy(engine_t *self, enemy_t *enemy) { + if (!self->waves->count) + if (!setup_wave(self, 0, 0)) + return 0; + + wave_t *wave = array_last(self->waves); + return wave_add_enemy(wave, enemy); +} + diff --git a/src/tdef/engine.h b/src/tdef/engine.h index f01856e..0b537ba 100644 --- a/src/tdef/engine.h +++ b/src/tdef/engine.h @@ -15,6 +15,7 @@ #include #include "cutils/array.h" #include "map.h" +#include "wave.h" /** * @brief bla @@ -25,9 +26,10 @@ typedef struct { char CNAME[10]; map_t *map; size_t current_tick; - array_t *enemies; - array_t *events; + array_t *waves; // wave_t + array_t *events; // event_t enemy_t *last_enemy; + int current_wave; int life; } engine_t; @@ -80,5 +82,7 @@ void engine_tick(engine_t *self); int setup_enemy(engine_t *self, enemy_t *enemy); +int setup_wave(engine_t *self, int start_tick, int bits); + #endif /* ENGINE_H */ diff --git a/src/tdef/event.c b/src/tdef/event.c index 4c385ef..e707238 100644 --- a/src/tdef/event.c +++ b/src/tdef/event.c @@ -67,6 +67,7 @@ const char *event_name(event_t *self) { case MOVE : return "MOVE" ; case DIE : return "DIE" ; case BREACH : return "BREACH" ; + case WAVE : return "WAVE" ; case WIN : return "WIN" ; case LOOSE : return "LOOSE" ; } diff --git a/src/tdef/event.h b/src/tdef/event.h index 0b4b096..7a90d29 100644 --- a/src/tdef/event.h +++ b/src/tdef/event.h @@ -27,6 +27,7 @@ typedef enum { MOVE, DIE, BREACH, + WAVE, WIN, LOOSE, } event_type; diff --git a/src/tdef/map.c b/src/tdef/map.c index 5984668..c4f5047 100644 --- a/src/tdef/map.c +++ b/src/tdef/map.c @@ -103,6 +103,7 @@ void map_enemy_enters(map_t *self, enemy_t *enemy, array_t *events) { event_t event; init_event(&event, ENTER); + event.x = enemy->id; array_push(events, &event); return; @@ -120,8 +121,8 @@ void map_move_1(map_t *self, array_t *events) { if (dead > (self->alive->count / 2)) { array_clear(self->tmp_e); - array_loop(self->alive, ptr, enemy_t*) { - if((*ptr)->alive) + array_loop (self->alive, ptr, enemy_t*) { + if ((*ptr)->alive) array_push(self->tmp_e, ptr); } array_steal_data(self->alive, self->tmp_e); diff --git a/src/tdef/tdef.c b/src/tdef/tdef.c index fc6bd6a..a87d502 100644 --- a/src/tdef/tdef.c +++ b/src/tdef/tdef.c @@ -70,7 +70,10 @@ void output_event(event_t *self, FILE *file) { case BACKFILL: case DIE: case BREACH: fprintf(file, "EVENT:%s,%d,%d\n", name, self->x, self->y); break; - case ENTER: case WIN: case LOOSE: + case ENTER: case WAVE: + fprintf(file, "EVENT:%s,%d\n", name, self->x); + break; + case WIN: case LOOSE: fprintf(file, "EVENT:%s\n", name); break; } @@ -101,7 +104,7 @@ int main(int argc, char **argv) { tower_t *tower = new_tower(2, 1); setup_tower(map, tower); - enemy_t *enemy = new_enemy(1); + enemy_t *enemy = new_enemy(0, 1); enemy->speed = 1; setup_enemy(engine, enemy); @@ -117,7 +120,7 @@ int main(int argc, char **argv) { } if (displayMode) { fprintf(stderr, - "Tick is: %d\n", engine->current_tick); + "Tick is: %zu\n", engine->current_tick); display(map); } break; @@ -125,7 +128,7 @@ int main(int argc, char **argv) { displayMode = !displayMode; if (displayMode) { fprintf(stderr, - "Tick is: %d\n", engine->current_tick); + "Tick is: %zu\n", engine->current_tick); display(map); } break; diff --git a/src/tdef/wave.c b/src/tdef/wave.c new file mode 100644 index 0000000..332c9a3 --- /dev/null +++ b/src/tdef/wave.c @@ -0,0 +1,106 @@ +/* + * 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 . + */ + +#include +#include + +#include "wave.h" + +wave_t *new_wave(size_t start_tick) { + wave_t *self = malloc(sizeof(wave_t)); + if (!init_wave(self, start_tick)) { + free(self); + self = NULL; + } + + return self; +} + +int init_wave(wave_t *self, size_t start_tick) { + size_t sz = sizeof(self->CNAME); + strncpy(self->CNAME, "[wave ", sz); + self->CNAME[sz - 2] = ']'; + self->CNAME[sz - 1] = '\0'; + + self->start_tick = start_tick; + self->enemies = new_array(sizeof(enemy_t), 20); + self->tmp_e = new_array(sizeof(enemy_t), 20); + self->last_enemy = NULL; + self->bits = 0; + self->done = 0; + + return 1; +} + +void free_wave(wave_t *self) { + if (self) + uninit_wave(self); + + free(self); +} + +void uninit_wave(wave_t *self) { + self->CNAME[0] = '!'; + + if (self->enemies) { + array_loop(self->enemies, enemy, enemy_t) { + uninit_enemy(enemy); + } + } + + free_array(self->enemies); self->enemies = NULL; + free_array(self->tmp_e) ; self->tmp_e = NULL; + self->last_enemy = NULL; +} + +int wave_add_enemy(wave_t *self, enemy_t *enemy) { + if (!array_push(self->enemies, enemy)) + return 0; + return 1; +} + +enemy_t *wave_next_enemy(wave_t *self, int tick) { + if (self->done) + return NULL; + + enemy_t *enemy; + if (!self->last_enemy) + enemy = array_first(self->enemies); + else + enemy = array_next(self->enemies, self->last_enemy); + + if (enemy && (self->start_tick + enemy->start_tick) >= tick) { + self->last_enemy = enemy; + return enemy; + } + + int dead = 0; + array_loop (self->enemies, enemy, enemy_t) { + if (!enemy->alive) + dead++; + } + + if (dead == self->enemies->count) { + self->done = 1; + } + + return NULL; +} + + diff --git a/src/tdef/wave.h b/src/tdef/wave.h new file mode 100644 index 0000000..38bd41e --- /dev/null +++ b/src/tdef/wave.h @@ -0,0 +1,80 @@ +/** + * @file wave.h + * @author Niki + * @date 2025 + * + * @brief bla + * + * blablabla + * + */ + +#ifndef WAVE_H +#define WAVE_H + +#include +#include "cutils/array.h" +#include "enemy.h" + +/** + * @brief bla + * + * blablabla + */ +typedef struct { + char CNAME[10]; + size_t start_tick; + array_t *enemies; // enemy_t + array_t *tmp_e; // enemy_t + enemy_t *last_enemy; + int bits; + int done; +} wave_t; + +/** + * Create a new wave. + * + * @param start_tick the tick at which the wave will start on the map + * + * @note always identical to malloc + init_wave + * + * @see malloc() + * @see init_wave(wave_t *self) + * + * @return a new wave (you must later call `free_wave()`) + */ +wave_t *new_wave(size_t start_tick); + +/** + * Initialise a new wave. + * + * @param start_tick the tick at which the wave will start on the map + */ +int init_wave(wave_t *self, size_t start_tick); + +/** + * Free the resources held for the given wave: you must not use it any more. + * + * @note always equivalent to uninit_wave + free + * + * @see uninit_wave(wave_t *self) + * @see free(void *data) + */ +void free_wave(wave_t *self); + +/** + * Free the resources held for the given wave: you must not use it any more + * unless you call init_wave on it again. + * + * The memory pointed to by self is not free'd. + * + * + * @see init_wave(wave_t *self) + */ +void uninit_wave(wave_t *self); + +int wave_add_enemy(wave_t *self, enemy_t *enemy); + +enemy_t *wave_next_enemy(wave_t *self, int tick); + +#endif /* WAVE_H */ -- 2.27.0