--- /dev/null
+/*
+ * TDef: small command 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 "cutils/cstring.h"
+#include "command.h"
+
+
+command_t *new_command(command_type type) {
+ command_t *self = malloc(sizeof(command_t));
+ if (!init_command(self, type)) {
+ free(self);
+ self = NULL;
+ }
+
+ return self;
+}
+
+int init_command(command_t *self, command_type type) {
+ size_t sz = sizeof(self->CNAME);
+ strncpy(self->CNAME, "[command ", sz);
+ self->CNAME[sz - 2] = ']';
+ self->CNAME[sz - 1] = '\0';
+
+ self->type = type;
+
+ return 1;
+}
+
+void free_command(command_t *self) {
+ if (self)
+ uninit_command(self);
+
+ free(self);
+}
+
+void uninit_command(command_t *self) {
+ self->CNAME[0] = '!';
+}
+
--- /dev/null
+/**
+ * @file command.h
+ * @author Niki
+ * @date 2025
+ *
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+#include <stdio.h>
+#include "cutils/array.h"
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef enum {
+ TICK,
+ DISPLAY,
+ UNKNOWN,
+ QUIT
+} command_type;
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef struct {
+ char CNAME[10];
+ command_type type;
+ array_t *data;
+} command_t;
+
+/**
+ * Create a new command.
+ *
+ * @param type the command type
+ *
+ * @note always identical to <tt>malloc</tt> + <tt>init_command</tt>
+ *
+ * @see malloc()
+ * @see init_command(command_t *self)
+ *
+ * @return a new command (you must later call `free_command()`)
+ */
+command_t *new_command(command_type type);
+
+/**
+ * Initialise a new command.
+ *
+ * @param type the command type
+ */
+int init_command(command_t *self, command_type type);
+
+/**
+ * Free the resources held for the given command: you must not use it any more.
+ * The map will also be free'd.
+ *
+ * @note always equivalent to <tt>uninit_command</tt> + <tt>free</tt>
+ *
+ * @see uninit_command(command_t *self)
+ * @see free(void *data)
+ */
+void free_command(command_t *self);
+
+/**
+ * Free the resources held for the given command: you must not use it any more
+ * unless you call <tt>init_command</tt> on it again.
+ * The map will also be free'd.
+ *
+ * The memory pointed to by <tt>self</tt> is <i>not</i> free'd.
+ *
+ *
+ * @see init_command(command_t *self)
+ */
+void uninit_command(command_t *self);
+
+#endif /* COMMAND_H */
+
}
return "Unknown";
}
+
+void event_output(event_t *self, cstring_t *out) {
+ const char *name = event_name(self);
+
+ switch (self->type) {
+ case FIRE: case HIT: case MOVE:
+ cstring_addp(out, "EVENT:%s,%d,%d,%d,%d\n", name,
+ self->x, self->y, self->move_to_x, self->move_to_y);
+ break;
+ case BACKFILL: case DIE: case BREACH:
+ cstring_addp(out, "EVENT:%s,%d,%d\n", name, self->x, self->y);
+ break;
+ case ENTER: case WAVE:
+ cstring_addp(out, "EVENT:%s,%d\n", name, self->x);
+ break;
+ case WIN: case LOOSE:
+ cstring_addp(out, "EVENT:%s\n", name);
+ break;
+ }
+}
+
#define EVENT_H
#include <stddef.h>
+#include "cutils/cstring.h"
/**
* @brief bla
const char *event_name(event_t *self);
+void event_output(event_t *self, cstring_t *out);
+
#endif /* EVENT_H */
/*
- * TDef: small tower defense game
+ * TDef: small reader defense game
*
* Copyright (C) 2025 Niki Roo
*
// TODO: configuration:
// map size
-// path: (1,1), (1,2)...
+// path: 1,1;1,2;1,3;
// basic: setMoney, setLife, start...
// tower: configTower('1', ...)
// enemy: configEnemy('a', ...)
-// TODO:
-// display: could be a mode (auto after tick)
-
-command read_command(FILE *file) {
+command_t *reader_readnext(FILE *file) {
static cstring_t *line = NULL;
-
if (!line)
line = new_cstring();
+ command_t *cmd = NULL;
+
if (cstring_readline(line, file)) {
+ cmd = new_command(UNKNOWN);
+
if (!strcmp(".", line->string)) {
- return TICK;
- } else if (!strcmp("display", line->string)) {
- return DISPLAY;
- } else {
- return UNKNOWN;
+ cmd->type = TICK;
+ } else if (cstring_starts_with("display", line->string, 0)) {
+ cmd->type = DISPLAY;
+ } else if (cstring_starts_with("quit", line->string, 0)) {
+ cmd->type = QUIT;
}
}
- return QUIT;
+ return cmd;
}
#define READER_H
#include <stdio.h>
+#include "command.h"
-typedef enum {
- TICK,
- DISPLAY,
- UNKNOWN,
- QUIT
-} command;
-
-command read_command(FILE *file);
+// NULL = eof
+command_t *reader_readnext(FILE *file);
#endif /* READER_H */
#include "reader.h"
#include "event.h"
+int displayMode = 0;
+
void display(map_t *self) {
fprintf(stderr, "==========\n\n");
for (int y = 0 ; y < self->height; y++) {
fprintf(stderr, "\n");
}
-void output_event(event_t *self, FILE *file) {
- const char *name = event_name(self);
+int process_cmd(command_t *cmd, engine_t *engine) {
+ static cstring_t *out = NULL;
+ if (!out)
+ out = new_cstring();
- switch (self->type) {
- case FIRE: case HIT: case MOVE:
- fprintf(file, "EVENT:%s,%d,%d,%d,%d\n", name,
- self->x, self->y, self->move_to_x, self->move_to_y);
- break;
- case BACKFILL: case DIE: case BREACH:
- fprintf(file, "EVENT:%s,%d,%d\n", name, self->x, self->y);
+ switch(cmd->type) {
+ case TICK:
+ engine_tick(engine);
+ array_loop(engine->events, event, event_t) {
+ event_output(event, out);
+ fprintf(stdout, "%s", out->string);
+ cstring_clear(out);
+ }
+ if (displayMode) {
+ fprintf(stderr,
+ "Tick is: %zu\n", engine->current_tick);
+ display(engine->map);
+ }
break;
- case ENTER: case WAVE:
- fprintf(file, "EVENT:%s,%d\n", name, self->x);
+ case DISPLAY:
+ displayMode = !displayMode;
+ if (displayMode) {
+ fprintf(stderr,
+ "Tick is: %zu\n", engine->current_tick);
+ display(engine->map);
+ }
break;
- case WIN: case LOOSE:
- fprintf(file, "EVENT:%s\n", name);
+ case UNKNOWN:
+ fprintf(stderr, "Unrecognized command\n");
break;
+ case QUIT:
+ return 0;
}
+
+ return 1;
}
int main(int argc, char **argv) {
map_t *map = new_map(6, 4);
- if (!map) {
- fprintf(stderr, "Cannot create the map");
- return 1;
- }
-
engine_t *engine = new_engine(map);
- if (!engine) {
- fprintf(stderr, "Cannot create the engine");
- return 2;
+ if (!map || !engine) {
+ fprintf(stderr, "Allocation error");
+ return 1;
}
setup_path(map, 0, 0);
enemy->speed = 1;
setup_enemy(engine, enemy);
-
- int displayMode = 0;
- command cmd = read_command(stdin);
- while (cmd != QUIT) {
- switch(cmd) {
- case TICK:
- engine_tick(engine);
- array_loop(engine->events, event, event_t) {
- output_event(event, stdout);
- }
- if (displayMode) {
- fprintf(stderr,
- "Tick is: %zu\n", engine->current_tick);
- display(map);
- }
- break;
- case DISPLAY:
- displayMode = !displayMode;
- if (displayMode) {
- fprintf(stderr,
- "Tick is: %zu\n", engine->current_tick);
- display(map);
- }
- break;
- case UNKNOWN:
- fprintf(stderr, "Unrecognized command\n");
- break;
- case QUIT:
- // cannot happen, but kept for warning purposes
- break;
+ command_t *cmd = reader_readnext(stdin);
+ while (cmd) {
+ if (process_cmd(cmd, engine)) {
+ free_command(cmd);
+ cmd = reader_readnext(stdin);
+ } else {
+ free_command(cmd);
+ cmd = NULL;
}
-
- cmd = read_command(stdin);
}
free_engine(engine);