prepare command system
authorNiki <niki@nikiroo.be>
Wed, 9 Apr 2025 06:45:43 +0000 (08:45 +0200)
committerNiki <niki@nikiroo.be>
Wed, 9 Apr 2025 06:45:43 +0000 (08:45 +0200)
src/tdef/command.c [new file with mode: 0644]
src/tdef/command.h [new file with mode: 0644]
src/tdef/event.c
src/tdef/event.h
src/tdef/reader.c
src/tdef/reader.h
src/tdef/tdef.c

diff --git a/src/tdef/command.c b/src/tdef/command.c
new file mode 100644 (file)
index 0000000..593a474
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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] = '!';
+}
+
diff --git a/src/tdef/command.h b/src/tdef/command.h
new file mode 100644 (file)
index 0000000..e5910e9
--- /dev/null
@@ -0,0 +1,86 @@
+/** 
+ * @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 */
+
index e7072386da1e15f6a15e4d8520326a3823da0eb1..8aed3952f602426e825c0f9053628f311cfb6aca 100644 (file)
@@ -73,3 +73,24 @@ const char *event_name(event_t *self) {
        }
        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;
+       }
+}
+
index 7a90d29209f1a414e688d04ece369252092c35b7..f647bfd95063168df101ee342e22ff85952e0fa1 100644 (file)
@@ -13,6 +13,7 @@
 #define EVENT_H
 
 #include <stddef.h>
+#include "cutils/cstring.h"
 
 /**
  * @brief bla
@@ -90,4 +91,6 @@ void uninit_event(event_t *self);
 
 const char *event_name(event_t *self);
 
+void event_output(event_t *self, cstring_t *out);
+
 #endif /* EVENT_H */
index dab3b465efb330e2745729c903297cae22936124..602218f0b08f76e49f9c9cfd5af94b4544c6e14e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * 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;
 }
 
index 5c6ea60fc479c7fdd627eb5ab166b8364524be87..c2a7a4822542306703d627d7c6ca1fc4f76a21d6 100644 (file)
 #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 */
 
index a87d50228e21f5dddc9b81cd56c28eaae059655a..9a3d6b880814797ff0cb4f7fc1621ad28c9c1e08 100644 (file)
@@ -27,6 +27,8 @@
 #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++) {
@@ -59,37 +61,49 @@ void display(map_t *self) {
        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);
@@ -108,39 +122,15 @@ int main(int argc, char **argv) {
        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);