#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;
}
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;
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
/**
* 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 <tt>malloc</tt> + <tt>init_enemy</tt>
*
* @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.
#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)) {
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;
}
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);
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);
+}
+
#include <stddef.h>
#include "cutils/array.h"
#include "map.h"
+#include "wave.h"
/**
* @brief bla
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;
int setup_enemy(engine_t *self, enemy_t *enemy);
+int setup_wave(engine_t *self, int start_tick, int bits);
+
#endif /* ENGINE_H */
case MOVE : return "MOVE" ;
case DIE : return "DIE" ;
case BREACH : return "BREACH" ;
+ case WAVE : return "WAVE" ;
case WIN : return "WIN" ;
case LOOSE : return "LOOSE" ;
}
MOVE,
DIE,
BREACH,
+ WAVE,
WIN,
LOOSE,
} event_type;
event_t event;
init_event(&event, ENTER);
+ event.x = enemy->id;
array_push(events, &event);
return;
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);
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;
}
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);
}
if (displayMode) {
fprintf(stderr,
- "Tick is: %d\n", engine->current_tick);
+ "Tick is: %zu\n", engine->current_tick);
display(map);
}
break;
displayMode = !displayMode;
if (displayMode) {
fprintf(stderr,
- "Tick is: %d\n", engine->current_tick);
+ "Tick is: %zu\n", engine->current_tick);
display(map);
}
break;
--- /dev/null
+/*
+ * 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 "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;
+}
+
+
--- /dev/null
+/**
+ * @file wave.h
+ * @author Niki
+ * @date 2025
+ *
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef WAVE_H
+#define WAVE_H
+
+#include <stddef.h>
+#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 <tt>malloc</tt> + <tt>init_wave</tt>
+ *
+ * @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 <tt>uninit_wave</tt> + <tt>free</tt>
+ *
+ * @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 <tt>init_wave</tt> on it again.
+ *
+ * The memory pointed to by <tt>self</tt> is <i>not</i> 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 */