some code and cutils
authorNiki Roo <niki@nikiroo.be>
Fri, 4 Apr 2025 22:51:25 +0000 (00:51 +0200)
committerNiki Roo <niki@nikiroo.be>
Fri, 4 Apr 2025 22:51:25 +0000 (00:51 +0200)
18 files changed:
.gitmodules [new file with mode: 0644]
Makefile
src/cutils [new submodule]
src/tdef/Makefile [new file with mode: 0755]
src/tdef/any.c [new file with mode: 0644]
src/tdef/any.h [new file with mode: 0644]
src/tdef/enemy.c [new file with mode: 0644]
src/tdef/enemy.h [new file with mode: 0644]
src/tdef/engine.c [new file with mode: 0644]
src/tdef/engine.h [new file with mode: 0644]
src/tdef/makefile.d [new file with mode: 0755]
src/tdef/map.c [new file with mode: 0644]
src/tdef/map.h [new file with mode: 0644]
src/tdef/path.c [new file with mode: 0644]
src/tdef/path.h [new file with mode: 0644]
src/tdef/tdef.c [new file with mode: 0644]
src/tdef/tower.c [new file with mode: 0644]
src/tdef/tower.h [new file with mode: 0644]

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..abd99b7
--- /dev/null
@@ -0,0 +1,4 @@
+[submodule "src/cutils"]
+       path = src/cutils
+       url = git@git.nikiroo.be:workspace/cutils.git
+       branch = subtree
index 790beea3a6d2827fa2cd1f954dfb320070ad34b9..44eac28013c0d31e8d358faa634a54a94e5a45c9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,9 +4,9 @@
 # > NAMES: list of all the programs to compile
 # > TESTS: list of all test programs to compile and run
 #
-NAME   = program
-NAMES  = $(NAME) program2
-TESTS  = tests-program
+NAME   = tdef
+NAMES  = $(NAME)
+TESTS  = 
 
 ################################################################################
 
diff --git a/src/cutils b/src/cutils
new file mode 160000 (submodule)
index 0000000..d6fa07c
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit d6fa07c12023662e16ace68bba78047e0244a9f7
diff --git a/src/tdef/Makefile b/src/tdef/Makefile
new file mode 100755 (executable)
index 0000000..4b2abfa
--- /dev/null
@@ -0,0 +1,10 @@
+# Simply pass everything to makefile.d, but calling from "../"
+
+.PHONY: default $(MAKECMDGOALS)
+
+default $(MAKECMDGOALS):
+       @for mk in makefile.d; do \
+               $(MAKE) --no-print-directory -C ../ -f "$(CURDIR)/$$mk" \
+                       $(MAKECMDGOALS); \
+       done;
+
diff --git a/src/tdef/any.c b/src/tdef/any.c
new file mode 100644 (file)
index 0000000..0315baa
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 "any.h"
+
+path_t *anyloc(any_t *self) {
+       if (self && self->_.type == 'l')
+               return (path_t*)(void*)self;
+       return NULL;
+}
+
+tower_t *anytower(any_t *self) {
+       if (self && self->_.type == 't')
+               return (tower_t*)(void*)self;
+       return NULL;
+}
+
+enemy_t *anyenemy(any_t *self) {
+       if (self && self->_.type == 'e')
+               return (enemy_t*)(void*)self;
+       return NULL;
+}
+
+any_t *loc2any(path_t *self) {
+       return (any_t*)(void*)self;
+}
+
+any_t *tower2any(tower_t *self) {
+       return (any_t*)(void*)self;
+}
+
+any_t *enemy2any(enemy_t *self) {
+       return (any_t*)(void*)self;
+}
+
diff --git a/src/tdef/any.h b/src/tdef/any.h
new file mode 100644 (file)
index 0000000..33a755e
--- /dev/null
@@ -0,0 +1,44 @@
+/** 
+ * @file any.h
+ * @author Niki
+ * @date 2025
+ * 
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef ANY_H
+#define ANY_H
+
+#include "path.h"
+#include "tower.h"
+#include "enemy.h"
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef union {
+       struct { char _; char type; } _;
+       path_t _l;
+       tower_t _t;
+       enemy_t _e;
+} any_t;
+
+path_t *anyloc(any_t *self);
+
+tower_t *anytower(any_t *self);
+
+enemy_t *anyenemy(any_t *self);
+
+any_t *loc2any(path_t *self);
+
+any_t *tower2any(tower_t *self);
+
+any_t *enemy2any(enemy_t *self);
+
+#endif /* ANY_H */
+
diff --git a/src/tdef/enemy.c b/src/tdef/enemy.c
new file mode 100644 (file)
index 0000000..b611728
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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 "enemy.h"
+
+enemy_t *new_enemy(size_t start_tick) {
+       enemy_t *self = malloc(sizeof(enemy_t));
+       if (!init_enemy(self, start_tick)) {
+               free(self);
+               self = NULL;
+       }
+
+       return self;
+}
+
+int init_enemy(enemy_t *self, 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;
+       
+       return 1;
+}
+
+void free_enemy(enemy_t *self) {
+       if (self)
+               uninit_enemy(self);
+
+       free(self);
+}
+
+void uninit_enemy(enemy_t *self) {
+       self->CNAME[0] = '!';
+}
+
diff --git a/src/tdef/enemy.h b/src/tdef/enemy.h
new file mode 100644 (file)
index 0000000..5702326
--- /dev/null
@@ -0,0 +1,71 @@
+/** 
+ * @file enemy.h
+ * @author Niki
+ * @date 2025
+ * 
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef ENEMY_H
+#define ENEMY_H
+
+#include <stddef.h>
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef struct {
+       char CNAME[10];
+       size_t start_tick;
+       int hp;
+       int speed; // paths per tick
+} enemy_t;
+
+/**
+ * Create a new 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>
+ *
+ * @see malloc()
+ * @see init_enemy(enemy_t *self)
+ *
+ * @return a new enemy (you must later call `free_enemy()`)
+ */
+enemy_t *new_enemy(size_t start_tick);
+
+/**
+ * Initialise a new 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);
+
+/** 
+ * Free the resources held for the given enemy: you must not use it any more.
+ *
+ * @note always equivalent to <tt>uninit_enemy</tt> + <tt>free</tt>
+ *
+ * @see uninit_enemy(enemy_t *self)
+ * @see free(void *data)
+ */
+void free_enemy(enemy_t *self);
+
+/**
+ * Free the resources held for the given enemy: you must not use it any more
+ * unless you call <tt>init_enemy</tt> on it again.
+ *
+ * The memory pointed to by <tt>self</tt> is <i>not</i> free'd.
+ *
+ *
+ * @see init_enemy(enemy_t *self)
+ */
+void uninit_enemy(enemy_t *self);
+
+#endif /* ENEMY_H */
diff --git a/src/tdef/engine.c b/src/tdef/engine.c
new file mode 100644 (file)
index 0000000..ca2c7ff
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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 "engine.h"
+
+void move(engine_t *self, enemy_t *enemy, path_t *path);
+
+engine_t *new_engine(map_t *map) {
+       engine_t *self = malloc(sizeof(engine_t));
+       if (!init_engine(self, map)) {
+               free(self);
+               self = NULL;
+       }
+
+       return self;
+}
+
+int init_engine(engine_t *self, map_t *map) {
+       size_t sz = sizeof(self->CNAME);
+       strncpy(self->CNAME, "[engine          ", sz);
+       self->CNAME[sz - 2] = ']';
+       self->CNAME[sz - 1] = '\0';
+       
+       self->map = map;
+       self->current_tick = 0;
+       self->events = new_array(sizeof(int), 10);
+       self->last_enemy = NULL;
+       
+       return (self->events != NULL);
+}
+
+void free_engine(engine_t *self) {
+       if (self)
+               uninit_engine(self);
+
+       free(self);
+}
+
+void uninit_engine(engine_t *self) {
+       self->CNAME[0] = '!';
+       free_map(self->map);
+       self->map = NULL;
+       free_array(self->events);
+       self->events = NULL;
+}
+
+void engine_tick(engine_t *self) {
+printf("Tick is: %d\n", self->current_tick);
+       array_clear(self->events);
+       
+       // TODO: all the rest
+       
+       enemy_t *enemy;
+       if (self->last_enemy)
+               enemy = array_next(self->map->enemies, self->last_enemy);
+       else
+               enemy = array_first(self->map->enemies);
+       
+       // We allow only one enemy per tick (because one per path!)
+       if (enemy->start_tick == self->current_tick) {
+               move(self, enemy, array_first(self->map->paths));
+       }
+       
+       self->current_tick++;
+}
+
+
+void move(engine_t *self, enemy_t *enemy, path_t *path) {
+       if (path->enemy)
+               printf("woops: TODO");
+       
+       path->enemy = enemy;
+}
+
diff --git a/src/tdef/engine.h b/src/tdef/engine.h
new file mode 100644 (file)
index 0000000..b19d6e9
--- /dev/null
@@ -0,0 +1,80 @@
+/** 
+ * @file engine.h
+ * @author Niki
+ * @date 2025
+ * 
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef ENGINE_H
+#define ENGINE_H
+
+#include <stddef.h>
+#include "cutils/array.h"
+#include "map.h"
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef struct {
+       char CNAME[10];
+       map_t *map;
+       size_t current_tick;
+       array_t *events;
+       enemy_t *last_enemy;
+} engine_t;
+
+/**
+ * Create a new engine.
+ *
+ * @param map the game map (will be owned by this engine)
+ *
+ * @note always identical to <tt>malloc</tt> + <tt>init_engine</tt>
+ *
+ * @see malloc()
+ * @see init_engine(engine_t *self)
+ *
+ * @return a new engine (you must later call `free_engine()`)
+ */
+engine_t *new_engine(map_t *map);
+
+/**
+ * Initialise a new engine.
+ *
+ * @param map the game map (will be owned by this engine)
+ */
+int init_engine(engine_t *self, map_t *map);
+
+/** 
+ * Free the resources held for the given engine: you must not use it any more.
+ * The map will also be free'd.
+ *
+ * @note always equivalent to <tt>uninit_engine</tt> + <tt>free</tt>
+ *
+ * @see uninit_engine(engine_t *self)
+ * @see free(void *data)
+ */
+void free_engine(engine_t *self);
+
+/**
+ * Free the resources held for the given engine: you must not use it any more
+ * unless you call <tt>init_engine</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_engine(engine_t *self)
+ */
+void uninit_engine(engine_t *self);
+
+// will clear events on start!
+void engine_tick(engine_t *self);
+
+#endif /* ENGINE_H */
+
diff --git a/src/tdef/makefile.d b/src/tdef/makefile.d
new file mode 100755 (executable)
index 0000000..c093aa2
--- /dev/null
@@ -0,0 +1,108 @@
+#
+# Makefile for C projets
+# > NAME   : the name of the main program (if programs, make a single .d file 
+#            per program, link them up in Makfile and use a $ssrcdir)
+# > srcdir : the source directory
+# > ssrcdir: the sub-sources directory (defaults to $srcdir)
+# > dstdir: the destination directory (defaults to $srcdir/bin)
+#
+# Environment variables:
+# > PREFIX: where to (un)install (defaults to /usr/local)
+# > DEBUG: define it to build with all debug symbols
+#
+NAME    = tdef
+srcdir  = $(NAME)
+ssrcdir = $(srcdir)
+
+# Note: c99+ required for for-loop initial declaration (not default in CentOS 6)
+# Note: gnu99 can be required for some projects (i.e.: libcutils-net)
+CFLAGS   += -Wall -pedantic -I./ -std=c99
+CXXFLAGS += -Wall -pedantic -I./
+PREFIX    =  /usr/local
+
+# Required libraries if any:
+# LDFLAGS += -lcheck $(shell pkg-config --libs --clfags check)
+
+# Required *locally compiled* libraries if any:
+# LIBS     = cutils
+LIBS     = cutils
+
+################################################################################
+
+ifeq ($(dstdir),)
+dstdir = $(srcdir)/bin
+endif
+
+ifdef DEBUG
+CFLAGS   += -ggdb -O0
+CXXFLAGS += -ggdb -O0
+endif
+
+# Default target
+.PHONY: all deps
+all:
+
+# locally compiled libs:
+ifneq ($(LIBS),)
+LDFLAGS   += -L$(dstdir)
+LDFLAGS   += $(foreach lib,$(LIBS),-l$(lib))
+endif
+deps:
+       $(foreach lib,$(LIBS),$(MAKE) --no-print-directory \
+                       -C $(lib)/ $(lib) dstdir=$(dstdir))
+
+.PHONY: build rebuild install uninstall clean mrpropre mrpropre \
+       $(NAME) test run run-test run-test-more
+
+SOURCES=$(wildcard $(ssrcdir)/*.c)
+OBJECTS=$(SOURCES:%.c=%.o)
+DEPENDS =$(SOURCES:%.c=%.d)
+
+# Autogenerate dependencies from code
+-include $(DEPENDS)
+%.o: %.c
+       $(CC) $(CFLAGS) -MMD -MP -c $< -o $@
+
+# Main targets
+
+all: build
+
+build: $(NAME)
+
+rebuild: clean build
+
+$(NAME): deps $(dstdir)/$(NAME)
+
+# Program, so no test
+run:
+       @echo
+       $(dstdir)/$(NAME) --help
+test run-test run-test-more:
+       @echo you are in the sources of the program, look at the tests instead
+
+$(dstdir)/$(NAME): $(OBJECTS)
+       mkdir -p $(dstdir)
+       # note: LDFLAGS *must* be near the end
+       $(CC) $(CFLAGS) $(OBJECTS) -o $@ $(LDFLAGS)
+
+clean:
+       $(foreach lib,$(LIBS),$(MAKE) --no-print-directory \
+                       -C $(lib)/ $@ dstdir=$(dstdir))
+       rm -f $(OBJECTS)
+       rm -f $(DEPENDS)
+
+mrproper: mrpropre
+mrpropre: clean
+       $(foreach lib,$(LIBS),$(MAKE) --no-print-directory \
+                       -C $(lib)/ $@ dstdir=$(dstdir))
+       rm -f $(dstdir)/$(NAME)
+       rmdir $(dstdir) 2>/dev/null || true
+
+install: build
+       mkdir -p "$(PREFIX)/bin"
+       cp "$(dstdir)/$(NAME)" "$(PREFIX)/bin/"
+
+uninstall:
+       rm "$(PREFIX)/bin/$(NAME)"
+       rmdir "$(PREFIX)/bin" 2>/dev/null
+
diff --git a/src/tdef/map.c b/src/tdef/map.c
new file mode 100644 (file)
index 0000000..91c31c8
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "map.h"
+
+map_t *new_map(int width, int height) {
+       map_t *self = malloc(sizeof(map_t));
+       if (!init_map(self, width, height)) {
+               free(self);
+               self = NULL;
+       }
+
+       return self;
+}
+
+int init_map(map_t *self, int width, int height) {
+       size_t sz = sizeof(self->CNAME);
+       strncpy(self->CNAME, "[map          ", sz);
+       self->CNAME[sz - 2] = ']';
+       self->CNAME[sz - 1] = '\0';
+       
+       self->width  = width;
+       self->height = height;
+       self->data   = calloc((width*height), sizeof(any_t*));
+       
+       self->paths   = new_array(sizeof(path_t   ), 100);
+       self->towers  = new_array(sizeof(tower_t*),  20);
+       self->enemies = new_array(sizeof(enemy_t ), 100);
+       self->alive   = new_array(sizeof(enemy_t*),  10);
+       
+       if (!self->data || !self->paths || !self->towers 
+               || !self->enemies || !self->alive
+       ) {
+               uninit_map(self);
+               return 0;
+       }
+       
+       return 1;
+}
+
+void free_map(map_t *self) {
+       if (self)
+               uninit_map(self);
+
+       free(self);
+}
+
+void uninit_map(map_t *self) {
+       self->CNAME[0] = '!';
+       
+       if (self->towers) {
+               array_loop(self->towers, tower, tower_t*) {
+                       free_tower(*tower);
+               }
+       }
+       
+       if (self->enemies) {
+               array_loop(self->enemies, enemy, enemy_t) {
+                       uninit_enemy(enemy);
+               }
+       }
+       
+       free      (self->data   ); self->data    = NULL;
+       free_array(self->paths  ); self->paths   = NULL;
+       free_array(self->towers ); self->towers  = NULL;
+       free_array(self->enemies); self->enemies = NULL;
+       free_array(self->alive)  ; self->alive   = NULL;
+}
+
+int map_path(map_t *self, int x, int y) {
+       if (x < 0 || y < 0)
+               return 0;
+       if (x >= self->width || y >= self->height)
+               return 0;
+       if (self->data[y * self->width + x])
+               return 0;
+       
+       path_t *loc = array_new(self->paths);
+       init_path(loc, x, y);
+       loc->index = self->paths->count - 1;
+       
+       self->data[y * self->width + x] = loc2any(loc);
+       return 1;
+}
+
+int map_add_tower(map_t *self, tower_t *tower) {
+       int x = tower->x;
+       int y = tower->y;
+       if (x < 0 || y < 0)
+               return 0;
+       if (x >= self->width || y >= self->height)
+               return 0;
+       if (self->data[y * self->width + x])
+               return 0;
+       
+       tower_t **ttt = array_new(self->towers);
+       *ttt = tower;
+       
+       self->data[y * self->width + x] = tower2any(tower);
+       return 1;
+}
+
+int map_enemy(map_t *self, enemy_t *enemy) {
+       if (!array_push(self->enemies, enemy))
+               return 0;
+       
+       return 1;
+}
+
diff --git a/src/tdef/map.h b/src/tdef/map.h
new file mode 100644 (file)
index 0000000..e8c4ff1
--- /dev/null
@@ -0,0 +1,86 @@
+/** 
+ * @file map.h
+ * @author Niki
+ * @date 2025
+ * 
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef MAP_H
+#define MAP_H
+
+#include "cutils/array.h"
+
+#include "any.h"
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef struct {
+       char CNAME[10];
+       int width;
+       int height;
+       any_t **data;
+       array_t *paths;
+       array_t *towers;
+       array_t *enemies;
+       array_t *alive;
+} map_t;
+
+/**
+ * Create a new map.
+ * 
+ * @param width the width of the map
+ * @param height the height of the map
+ *
+ * @note always identical to <tt>malloc</tt> + <tt>init_map</tt>
+ *
+ * @see malloc()
+ * @see init_map(map_t *self)
+ *
+ * @return a new map (you must later call `free_map()`)
+ */
+map_t *new_map(int width, int height);
+
+/**
+ * Initialise a new map.
+ *
+ * @param width the width of the map
+ * @param height the height of the map
+ */
+int init_map(map_t *self, int width, int height);
+
+/** 
+ * Free the resources held for the given map: you must not use it any more.
+ *
+ * @note always equivalent to <tt>uninit_map</tt> + <tt>free</tt>
+ *
+ * @see uninit_map(map_t *self)
+ * @see free(void *data)
+ */
+void free_map(map_t *self);
+
+/**
+ * Free the resources held for the given map: you must not use it any more
+ * unless you call <tt>init_map</tt> on it again.
+ *
+ * The memory pointed to by <tt>self</tt> is <i>not</i> free'd.
+ *
+ *
+ * @see init_map(map_t *self)
+ */
+void uninit_map(map_t *self);
+
+int map_path(map_t *self, int x, int y);
+
+int map_add_tower(map_t *self, tower_t *tower);
+
+int map_enemy(map_t *self, enemy_t *enemy);
+
+#endif /* MAP_H */
+
diff --git a/src/tdef/path.c b/src/tdef/path.c
new file mode 100644 (file)
index 0000000..0f8bb82
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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 "path.h"
+
+path_t *new_path(int x, int y) {
+       path_t *self = malloc(sizeof(path_t));
+       if (!init_path(self, x, y)) {
+               free(self);
+               self = NULL;
+       }
+
+       return self;
+}
+
+int init_path(path_t *self, int x, int y) {
+       size_t sz = sizeof(self->CNAME);
+       strncpy(self->CNAME, "[loc          ", sz);
+       self->CNAME[sz - 2] = ']';
+       self->CNAME[sz - 1] = '\0';
+       
+       self->x = x;
+       self->y = y;
+       self->index = -1;
+       self->enemy = NULL;
+       
+       return 1;
+}
+
+void free_path(path_t *self) {
+       if (self)
+               uninit_path(self);
+       
+       free(self);
+}
+
+void uninit_path(path_t *self) {
+       self->CNAME[0] = '!';
+}
+
diff --git a/src/tdef/path.h b/src/tdef/path.h
new file mode 100644 (file)
index 0000000..e4d8c22
--- /dev/null
@@ -0,0 +1,74 @@
+/** 
+ * @file path.h
+ * @author Niki
+ * @date 2025
+ * 
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef PATH_H
+#define PATH_H
+
+#include "enemy.h"
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef struct {
+       char CNAME[10];
+       int x;
+       int y;
+       int index;
+       enemy_t *enemy;
+} path_t;
+
+/**
+ * Create a new loc.
+ * 
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ *
+ * @note always identical to <tt>malloc</tt> + <tt>init_path</tt>
+ *
+ * @see malloc()
+ * @see init_path(path_t *self)
+ *
+ * @return a new loc (you must later call `free_path()`)
+ */
+path_t *new_path(int x, int y);
+
+/**
+ * Initialise a new loc.
+ * 
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ */
+int init_path(path_t *self, int x, int y);
+
+/** 
+ * Free the resources held for the given loc: you must not use it any more.
+ *
+ * @note always equivalent to <tt>uninit_path</tt> + <tt>free</tt>
+ *
+ * @see uninit_path(path_t *self)
+ * @see free(void *data)
+ */
+void free_path(path_t *self);
+
+/**
+ * Free the resources held for the given loc: you must not use it any more
+ * unless you call <tt>init_path</tt> on it again.
+ *
+ * The memory pointed to by <tt>self</tt> is <i>not</i> free'd.
+ *
+ *
+ * @see init_path(path_t *self)
+ */
+void uninit_path(path_t *self);
+
+#endif /* PATH_H */
diff --git a/src/tdef/tdef.c b/src/tdef/tdef.c
new file mode 100644 (file)
index 0000000..4c4b914
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "any.h"
+#include "map.h"
+#include "engine.h"
+
+void display(map_t *self) {
+       printf("==========\n\n");
+       for (int y = 0 ; y < self->height; y++) {
+       for (int x = 0 ; x < self->width ; x++) {
+               any_t *any = self->data[y * self->width + x];
+               path_t *path = anyloc(any);
+               tower_t *tower = anytower(any);
+               if (tower) {
+                       printf("T");
+               } else if (path) {
+                       if (path->enemy) {
+                               printf("e");
+                       }
+                       else if (path->index == 0) {
+                               printf(">");
+                       } else if (path->index == self->paths->count - 1) {
+                               printf(">");
+                       } else {
+                               printf("#");
+                       }
+               } else if (any) {
+                       printf("?");
+                       //printf("\n<%s>\n", any->CNAME);
+               } else {
+                       printf(".");
+               }
+       }
+       printf("\n");
+       }
+       printf("\n");
+}
+
+int main(int argc, char **argv) {
+       map_t *map = new_map(6, 4);
+       if (!map) {
+               fprintf(stderr, "Cannot create the map");
+               return 1;
+       }
+       
+       map_path(map, 0, 0);
+       map_path(map, 1, 0);
+       map_path(map, 2, 0);
+       map_path(map, 3, 0);
+       map_path(map, 3, 1);
+       map_path(map, 3, 2);
+       map_path(map, 4, 2);
+       map_path(map, 5, 2);
+       
+       tower_t *tower = new_tower(2, 1);
+       map_add_tower(map, tower);
+       
+       enemy_t *enemy = new_enemy(1);
+       map_enemy(map, enemy);
+       
+       engine_t *engine = new_engine(map);
+       engine_tick(engine);
+       
+       display(map);
+       engine_tick(engine);
+       display(map);
+       
+       free_engine(engine);
+       return 0;
+}
+
diff --git a/src/tdef/tower.c b/src/tdef/tower.c
new file mode 100644 (file)
index 0000000..40aa981
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 "tower.h"
+
+tower_t *new_tower(int x, int y) {
+       tower_t *self = malloc(sizeof(tower_t));
+       if (!init_tower(self, x, y)) {
+               free(self);
+               self = NULL;
+       }
+
+       return self;
+}
+
+int init_tower(tower_t *self, int x, int y) {
+       size_t sz = sizeof(self->CNAME);
+       strncpy(self->CNAME, "[tower          ", sz);
+       self->CNAME[sz - 2] = ']';
+       self->CNAME[sz - 1] = '\0';
+       
+       self->x = x;
+       self->y = y;
+       
+       return 1;
+}
+
+void free_tower(tower_t *self) {
+       if (self)
+               uninit_tower(self);
+
+       free(self);
+}
+
+void uninit_tower(tower_t *self) {
+       self->CNAME[0] = '!';
+}
+
diff --git a/src/tdef/tower.h b/src/tdef/tower.h
new file mode 100644 (file)
index 0000000..890b454
--- /dev/null
@@ -0,0 +1,70 @@
+/** 
+ * @file tower.h
+ * @author Niki
+ * @date 2025
+ * 
+ * @brief bla
+ *
+ * blablabla
+ *
+ */
+
+#ifndef TOWER_H
+#define TOWER_H
+
+/**
+ * @brief bla
+ *
+ * blablabla
+ */
+typedef struct {
+       char CNAME[10];
+       int x;
+       int y;
+} tower_t;
+
+/**
+ * Create a new tower.
+ *
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ *
+ * @note always identical to <tt>malloc</tt> + <tt>init_tower</tt>
+ *
+ * @see malloc()
+ * @see init_tower(tower_t *self)
+ *
+ * @return a new tower (you must later call `free_tower()`)
+ */
+tower_t *new_tower(int x, int y);
+
+/**
+ * Initialise a new tower.
+ *
+ * @param x the X coordinate
+ * @param y the Y coordinate
+ */
+int init_tower(tower_t *self, int x, int y);
+
+/** 
+ * Free the resources held for the given tower: you must not use it any more.
+ *
+ * @note always equivalent to <tt>uninit_tower</tt> + <tt>free</tt>
+ *
+ * @see uninit_tower(tower_t *self)
+ * @see free(void *data)
+ */
+void free_tower(tower_t *self);
+
+/**
+ * Free the resources held for the given tower: you must not use it any more
+ * unless you call <tt>init_tower</tt> on it again.
+ *
+ * The memory pointed to by <tt>self</tt> is <i>not</i> free'd.
+ *
+ *
+ * @see init_tower(tower_t *self)
+ */
+void uninit_tower(tower_t *self);
+
+#endif /* TOWER_H */