sw-battle-test-c

Interesting test task in C instead of C++
git clone git://bsandro.tech/sw-battle-test-c
Log | Files | Refs | README

commit 49f41b0f46038df870a67ed9cf8cfd5fbb3f90e5
parent a4e8747785682a4b4f016afe80fe9ec5d3231a8f
Author: bsandro <email@bsandro.tech>
Date:   Wed, 30 Sep 2026 01:53:13 +0300

somewhat working sim

Diffstat:
Mcommands/CREATE_MAP.c | 7++++---
Mcommands/MARCH.c | 21+++++++++++++++++++--
Mcommands/SPAWN_HUNTER.c | 42+++++++++++++++++++++++++++++++++++++++++-
Mcommands/SPAWN_SWORDSMAN.c | 55++++++++++---------------------------------------------
Mcore/command.h | 2+-
Mcore/parser.c | 25+++++++++++++++----------
Mcore/parser.h | 2+-
Mcore/world.c | 7+++++++
Mcore/world.h | 3++-
Mmain.c | 5++++-
10 files changed, 104 insertions(+), 65 deletions(-)

diff --git a/commands/CREATE_MAP.c b/commands/CREATE_MAP.c @@ -1,16 +1,17 @@ #include "core/command.h" static void create_map(World *w, int width, int height) { - printf("create_map(%p,%d,%d)\n", (void *)w, width, height); + //printf("create_map(%p,%d,%d)\n", (void *)w, width, height); Map_Init(&w->map, width, height); puts("map init ok"); } -void cmd_create_map(World *w, int argc, char **argv) { +bool cmd_create_map(World *w, int argc, char **argv) { if (argc!=2) { puts("cmd_create_map() invalid arguments"); - return; + return false; } create_map(w, atoi(argv[0]), atoi(argv[1])); + return true; } diff --git a/commands/MARCH.c b/commands/MARCH.c @@ -1,5 +1,22 @@ +#include "stb_ds.h" #include "core/command.h" +#include "actions/movement.h" -void cmd_march(World *w, ...) { - puts("march"); +static bool march(World *w, int id, int x, int y) { + Entity *e = World_Get_Entity(w, id); + if (e==NULL) return false; + Entity_Add_Component(e, (Component){ + .type = COMPONENT_MOVEMENT_TARGET, + .movement_target = { .x=x, .y=y } + }); + Component *actions = Entity_Find_Component(e, COMPONENT_ACTIONS); + if (actions==NULL) return false; + arrput(actions->actions.items, (struct Actions_Item){ .run = Action_Movement }); + puts("march ok"); + return true; +} + +bool cmd_march(World *w, int argc, char **argv) { + if (argc!=3) return false; + return march(w, atoi(argv[0]), atoi(argv[1]), atoi(argv[2])); } diff --git a/commands/SPAWN_HUNTER.c b/commands/SPAWN_HUNTER.c @@ -1,5 +1,45 @@ +#include "stb_ds.h" #include "core/command.h" +#include "core/ecs/entity.h" +#include "actions/attack_melee.h" +#include "actions/attack_ranged.h" +#include "actions/movement.h" -void cmd_spawn_hunter(World *w, ...) { +static void spawn_hunter(World *w, int id, int x, int y, int hp, int agi, int str, int range) { puts("spawn hunter"); + Entity hunter = {0}; + hunter.id = id; + Entity_Add_Component(&hunter, (Component){ + .type = COMPONENT_HEALTH, + .health = { .hp=hp } + }); + Entity_Add_Component(&hunter, (Component){ + .type = COMPONENT_MELEE, + .melee = { .strength=str } + }); + Entity_Add_Component(&hunter, (Component){ + .type = COMPONENT_POSITION, + .position = { .x=x, .y=y } + }); + Entity_Add_Component(&hunter, (Component){ + .type = COMPONENT_RANGED, + .ranged = { .agility=agi, .range=range } + }); + Actions actions = {0}; + arrput(actions.items, (struct Actions_Item){ .run = Action_Attack_Melee }); + arrput(actions.items, (struct Actions_Item){ .run = Action_Attack_Ranged }); + Entity_Add_Component(&hunter, (Component){ + .type = COMPONENT_ACTIONS, + .actions = actions + }); + World_Add_Entity(w, &hunter); + printf("unit has %ld components:\n", arrlen(hunter.components)); + printf("%d: %dhp\n", hunter.components[0].type, hunter.components[0].health.hp); +} + + +bool cmd_spawn_hunter(World *w, int argc, char **argv) { + if (argc!=7) return false; + spawn_hunter(w, atoi(argv[0]), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), atoi(argv[5]), atoi(argv[6])); + return true; } diff --git a/commands/SPAWN_SWORDSMAN.c b/commands/SPAWN_SWORDSMAN.c @@ -5,63 +5,24 @@ #include "actions/attack_ranged.h" #include "actions/movement.h" -static void spawn_ranger(World *w) { - //@todo parse va_args - puts("spawn ranger"); - Entity ranger = {0}; - ranger.id = 2; - Entity_Add_Component(&ranger, (Component){ - .type = COMPONENT_HEALTH, - .health = { .hp=30 } - }); - Entity_Add_Component(&ranger, (Component){ - .type = COMPONENT_MELEE, - .melee = { .strength=1 } - }); - Entity_Add_Component(&ranger, (Component){ - .type = COMPONENT_POSITION, - .position = { .x=1, .y=1 } - }); - Entity_Add_Component(&ranger, (Component){ - .type = COMPONENT_RANGED, - .ranged = { .agility=1, .range=6 } - }); - Actions actions = {0}; - arrput(actions.items, (struct Actions_Item){ .run = Action_Attack_Melee }); - arrput(actions.items, (struct Actions_Item){ .run = Action_Attack_Ranged }); - Entity_Add_Component(&ranger, (Component){ - .type = COMPONENT_ACTIONS, - .actions = actions - }); - World_Add_Entity(w, &ranger); - printf("unit has %ld components:\n", arrlen(ranger.components)); - printf("%d: %dhp\n", ranger.components[0].type, ranger.components[0].health.hp); -} - -void cmd_spawn_swordsman(World *w, ...) { - //@todo parse va_args +static void spawn_swordsman(World *w, int id, int x, int y, int hp, int str) { puts("spawn swordsman"); Entity swordsman = {0}; - swordsman.id = 1; + swordsman.id = id; Entity_Add_Component(&swordsman, (Component){ .type = COMPONENT_HEALTH, - .health = { .hp=30 } + .health = { .hp=hp } }); Entity_Add_Component(&swordsman, (Component){ .type = COMPONENT_MELEE, - .melee = { .strength=2 } + .melee = { .strength=str } }); Entity_Add_Component(&swordsman, (Component){ .type = COMPONENT_POSITION, - .position = { .x=8, .y=5 } - }); - Entity_Add_Component(&swordsman, (Component){ - .type = COMPONENT_MOVEMENT_TARGET, - .movement_target = { .x=2, .y=1 } + .position = { .x=x, .y=y } }); Actions actions = {0}; arrput(actions.items, (struct Actions_Item){ .run = Action_Attack_Melee }); - arrput(actions.items, (struct Actions_Item){ .run = Action_Movement }); Entity_Add_Component(&swordsman, (Component){ .type = COMPONENT_ACTIONS, .actions = actions @@ -69,6 +30,10 @@ void cmd_spawn_swordsman(World *w, ...) { World_Add_Entity(w, &swordsman); printf("unit has %ld components:\n", arrlen(swordsman.components)); printf("%d: %dhp\n", swordsman.components[0].type, swordsman.components[0].health.hp); +} - spawn_ranger(w); +bool cmd_spawn_swordsman(World *w, int argc, char **argv) { + if (argc!=5) return false; + spawn_swordsman(w, atoi(argv[0]), atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4])); + return true; } diff --git a/core/command.h b/core/command.h @@ -7,7 +7,7 @@ #define MAX_CMD_NAME_LEN 64 #define MAX_CMD_ARG_LEN 8 -typedef void Command_Func(World *w, int argc, char **argv); +typedef bool Command_Func(World *w, int argc, char **argv); typedef struct Command { const char *name; diff --git a/core/parser.c b/core/parser.c @@ -5,7 +5,14 @@ #include "core/parser.h" #include "commands/_registry.h" -void try_parse_call(World *w, char *line) { +static void arg_cleanup(int argc, char **argv) { + for (int i=0;i<argc;++i) { + free(argv[i]); + } + free(argv); +} + +bool try_parse_call(World *w, char *line) { char *saveptr = NULL; char cmd[MAX_CMD_NAME_LEN] = {0}; int argc = -1; @@ -13,7 +20,7 @@ void try_parse_call(World *w, char *line) { for (char *src=line;;src=NULL) { char *token=strtok_r(src, " \r\n", &saveptr); if (token==NULL) break; - printf(" -> %s", token); + //printf(" -> %s", token); int token_len = strlen(token); if (argc==-1) { strncpy(cmd, token, MAX_CMD_NAME_LEN-1); @@ -25,17 +32,15 @@ void try_parse_call(World *w, char *line) { argv[argc-1] = strndup(token, MAX_CMD_ARG_LEN-1); } } - printf("\n argc: %d\n---------\n", argc); + //printf("\n argc: %d\n---------\n", argc); + bool success = false; for (int i=0;i<COMMANDS_COUNT;++i) { if (strncmp(COMMANDS[i].name, cmd, MAX_CMD_NAME_LEN)==0) { - COMMANDS[i].func(w, argc, argv); - //goto fin; + success = COMMANDS[i].func(w, argc, argv); break; } } - // cleanup - for (int i=0;i<argc;++i) { - free(argv[i]); - } - free(argv); + + arg_cleanup(argc, argv); + return success; } diff --git a/core/parser.h b/core/parser.h @@ -1,3 +1,3 @@ #pragma once -void try_parse_call(World *w, char *line); +bool try_parse_call(World *w, char *line); diff --git a/core/world.c b/core/world.c @@ -21,3 +21,10 @@ bool World_Run_Systems(World *w) { } return ret; } + +Entity * World_Get_Entity(World *w, int id) { + for (int i=0;i<arrlen(w->entities);++i) { + if (w->entities[i].id == id) return &w->entities[i]; + } + return NULL; +} diff --git a/core/world.h b/core/world.h @@ -7,11 +7,12 @@ typedef struct World { Map map; - Entity *entities; + Entity *entities; //@todo hashmap instead of array System *systems; } World; World * World_Init(); void World_Add_Entity(World *w, Entity *e); +Entity * World_Get_Entity(World *w, int id); void World_Add_System(World *w, System *s); bool World_Run_Systems(World *w); diff --git a/main.c b/main.c @@ -22,7 +22,10 @@ int main(int argc, char **argv) { while ((slen=getline(&line, &linesize, f))!=-1) { if (slen==1) continue; //printf("[%zd] %s", slen, line); - try_parse_call(&w, line); + if (!try_parse_call(&w, line)) { + printf("invalid command %s\n", line); + return 1; + } } free(line); fclose(f);