added layered map, fixed item select with 0 items
Minclude/game.h
@@ -5,7 +5,28 @@
#include <assert.h>
#include <helper.h>
#include <darray.h>
#define MAXITEMS 10
#define MAX(x,y) (x >= y ? x : y)
#define MIN(x,y) (x <= y ? x : y)
#define ORC (struct monster)\
{\
.symbol = 'O',\
.name = "Zog Zog", \
.id = m_id++, .current_hp = 10, .max_hp = 10, .dmg = 1,\
.level = 5 , .xp = 0, .items = darray_new(), .isplayer = false\
}
#define EMPTYFIELD (struct object)\
{\
.type = NOOBJ,\
.symbol = ' ',\
}
#define WALLFIELD (struct object)\
{\
.type = WALL,\
.symbol = '#',\
}
extern unsigned m_id;
@@ -24,8 +45,15 @@ struct use
unsigned restorehp;
};
struct object
{
enum objtype type;
char symbol;
};
struct item
{
struct object o;
const char *name;
enum itemtype type;
union
@@ -38,6 +66,7 @@ struct item
struct monster
{
char symbol;
const char *name;
unsigned id;
unsigned current_hp;
@@ -49,44 +78,37 @@ struct monster
bool isplayer;
};
static inline size_t item_len(const struct monster *m)
struct field
{
for(size_t i = 0; i < MAXITEMS; i++)
{
if(darray_item(m->items, i).type == NOITEM)
return i;
}
return MAXITEMS;
}
struct object
{
enum objtype type;
char symbol;
union
{
struct monster m;
struct item i;
} u;
struct object ground;
struct item it;
} *u;
struct monster m;
bool has_monster;
};
struct game
{
struct object *map;
struct field *map;
size_t xs, ys;
};
static inline struct object *game_at(const struct game *g, struct point p)
static inline struct field *game_at(const struct game *g, struct point p)
{
return &g->map[p.y * g->xs + p.x];
}
static inline struct game create_game(size_t y, size_t x)
{
struct game ret;
ret.map = xmalloc(x * y * sizeof * ret.map);
ret.map = xmalloc(x * y * sizeof(*ret.map));
for(size_t i = 0; i < x*y; i++)
{
ret.map[i].u = xmalloc(sizeof(*ret.map[i].u));
ret.map[i].has_monster = false;
}
ret.xs = x;
ret.ys = y;
@@ -99,8 +121,9 @@ static inline void delete_game(struct game *g)
{
for(size_t x = 0; x < g->xs; x++)
{
if(game_at(g, (struct point){y,x})->type == MONSTER)
darray_free(game_at(g, (struct point){y,x})->u.m.items);
if(game_at(g, (struct point){y,x})->has_monster)
darray_free(game_at(g, (struct point){y,x})->m.items);
free(game_at(g, (struct point){y,x})->u);
}
}
free(g->map);
@@ -118,27 +141,6 @@ struct choice
}u;
};
#define MAX(x,y) (x >= y ? x : y)
#define MIN(x,y) (x <= y ? x : y)
#define ORC (struct object)\
{\
.type = MONSTER,\
.symbol = 'O',\
.u.m = {"Zog Zog", m_id++, 10, 10, 1, 5 , 0, darray_new(), false}\
}
#define EMPTYFIELD (struct object)\
{\
.type = NOOBJ,\
.symbol = ' ',\
}
#define WALLFIELD (struct object)\
{\
.type = WALL,\
.symbol = '#',\
}
static inline struct point relative(struct point p, enum direction d)
{
switch(d)
@@ -169,8 +171,9 @@ static inline void spawn_enemy(struct game *g)
while(true)
{
struct point p = {randrange(0, g->ys), randrange(0, g->xs)};
if(in_bounds(g, p) && game_at(g, p)->type == NOOBJ) {
*game_at(g, p) = ORC;
if(in_bounds(g, p) && game_at(g, p)->u->ground.type != WALL && !game_at(g, p)->has_monster) {
game_at(g, p)->m = ORC;
game_at(g, p)->has_monster = true;
break;
}
}
Minclude/items.h
@@ -10,11 +10,11 @@
.u.i = {"Dagger of Darkness", EQUIP, {{0, 2, 0}}}\
};
#define HP_POTION (struct object)\
#define HP_POTION (struct item)\
{\
.type = ITEM,\
.symbol = 'p',\
.u.i = {"HP Potion", USE, {{5, 0, 0}}}\
.o.type = ITEM,\
.o.symbol = 'p',\
.name = "HP Potion", .type = USE, .u = {.u.restorehp = 10}\
};
static inline void spawn_item(struct game *g)
@@ -22,8 +22,8 @@ static inline void spawn_item(struct game *g)
while(true)
{
struct point p = {randrange(0, g->ys), randrange(0, g->xs)};
if(in_bounds(g, p) && game_at(g, p)->type == NOOBJ) {
*game_at(g, p) = HP_POTION;
if(in_bounds(g, p) && game_at(g, p)->u->ground.type == NOOBJ) {
game_at(g, p)->u->it = HP_POTION;
break;
}
}
Msrc/algorithm.c
@@ -14,8 +14,7 @@
#define UNVISITED '#'
#define VISITED ' '
#define WALL '#'
#define NOWALL ' '
typedef unsigned long size_t;
@@ -39,7 +38,7 @@ struct game make_maze(size_t y, size_t x)
struct game g = create_game(y, x);
char *maze = xmalloc(y * x + 1);
memset(maze, WALL, y * x);
memset(maze, UNVISITED, y * x);
maze[y * x] = '\0';
darray(struct point) stack = darray_new();
@@ -69,7 +68,7 @@ struct game make_maze(size_t y, size_t x)
struct point choice = unindexpoint(nb[c]);
struct point diff = {choice.y-current.y, choice.x-current.x};
*maze_at(maze, x, (struct point){index(current.y)+diff.y, index(current.x)+diff.x}) = NOWALL;
*maze_at(maze, x, (struct point){index(current.y)+diff.y, index(current.x)+diff.x}) = VISITED;
current = choice;
} else if(!darray_empty(stack)) {
current = darray_pop(stack);
@@ -82,15 +81,15 @@ struct game make_maze(size_t y, size_t x)
{
for(size_t j = 0; j < x; j++)
{
if(*maze_at(maze, x, (struct point){i,j}) == NOWALL)
*game_at(&g, (struct point){i,j}) = EMPTYFIELD;
if(*maze_at(maze, x, (struct point){i,j}) == VISITED)
game_at(&g, (struct point){i,j})->u->ground = EMPTYFIELD;
else
*game_at(&g, (struct point){i,j}) = WALLFIELD;
game_at(&g, (struct point){i,j})->u->ground = WALLFIELD;
}
}
game_at(&g, (struct point){y-2,x-2})->symbol = '*';
game_at(&g, (struct point){y-2,x-2})->type = TARGET;
game_at(&g, (struct point){y-2,x-2})->u->ground.symbol = '*';
game_at(&g, (struct point){y-2,x-2})->u->ground.type = TARGET;
darray_free(stack);
free(maze);
@@ -149,13 +148,13 @@ pointarr astar(struct game *g, struct point start, struct point target, size_t m
struct point left = (struct point){currentnode->p.y, currentnode->p.x-1};
struct point right = (struct point){currentnode->p.y, currentnode->p.x+1};
if(game_at(g,left)->type == NOOBJ || game_at(g,left)->type == MONSTER)
if(game_at(g,left)->u->ground.type == NOOBJ)
darray_append(children, left);
if(game_at(g,right)->type == NOOBJ || game_at(g,right)->type == MONSTER)
if(game_at(g,right)->u->ground.type == NOOBJ)
darray_append(children, right);
if(game_at(g,up)->type == NOOBJ || game_at(g,up)->type == MONSTER)
if(game_at(g,up)->u->ground.type == NOOBJ)
darray_append(children, up);
if(game_at(g,down)->type == NOOBJ || game_at(g,down)->type == MONSTER)
if(game_at(g,down)->u->ground.type == NOOBJ)
darray_append(children, down);
Msrc/loop.c
@@ -83,30 +83,24 @@ static void addxp(struct monster *m, unsigned xp)
}
}
static void attack(struct object *src, struct object *target)
static void attack(struct monster *src, struct field *target)
{
assert(src->type == MONSTER);
if(src->isplayer)
logstr("%s hit %s for %d damage", src->name, target->m.name, src->dmg);
if(src->dmg >= target->m.current_hp) {
logstr("%s killed %s", src->name ,target->m.name);
if(target->type == MONSTER) {
if(src->u.m.isplayer)
logstr("%s hit %s for %d damage", src->u.m.name, target->u.m.name, src->u.m.dmg);
if(src->u.m.dmg >= target->u.m.current_hp) {
logstr("%s killed %s", src->u.m.name ,target->u.m.name);
if(src->u.m.isplayer) {
addxp(&src->u.m, target->u.m.level*10);
} else {
messagebox("U done did dedden", 1, 0);
exit(0);
}
darray_free(target->u.m.items);
*target = NOOBJ_OBJECT;
if(src->isplayer) {
addxp(src, target->m.level*10);
} else {
target->u.m.current_hp -= src->u.m.dmg;
messagebox("U done did dedden", 1, 0);
exit(0);
}
darray_free(target->m.items);
target->has_monster = false;
} else {
logstr("Target is not a monster or player");
target->m.current_hp -= src->dmg;
}
}
@@ -153,17 +147,20 @@ void inventory(struct monster *m)
//TODO: player moves on target, create new map
struct point move_object(struct game *g, struct point src, struct point target)
{
if(game_at(g, target)->type == NOOBJ) {
*game_at(g, target) = *game_at(g, src);
*game_at(g, src) = NOOBJ_OBJECT;
if(game_at(g, target)->u->ground.type == NOOBJ && !game_at(g, target)->has_monster) {
game_at(g, target)->has_monster = true;
game_at(g, target)->m = game_at(g, src)->m;
game_at(g, src)->has_monster = false;
return target;
} else if(game_at(g, target)->type == ITEM && game_at(g, src)->type == MONSTER) {
if(!additem(&game_at(g, src)->u.m, &game_at(g, target)->u.i)) {
} else if(game_at(g, target)->u->ground.type == ITEM && !game_at(g, target)->has_monster && game_at(g, src)->has_monster) {
if(!additem(&game_at(g, src)->m, &game_at(g, target)->u->it)) {
logstr("Inventory is full");
return src;
}
*game_at(g, target) = *game_at(g, src);
*game_at(g, src) = NOOBJ_OBJECT;
game_at(g, target)->has_monster = true;
game_at(g, target)->m = game_at(g, src)->m;
game_at(g, target)->u->ground = EMPTYFIELD;
game_at(g, src)->has_monster = false;
return target;
} else {
return src;
@@ -172,10 +169,11 @@ struct point move_object(struct game *g, struct point src, struct point target)
static inline struct point attack_move(struct game *g, struct point src, struct point target)
{
struct object *t = game_at(g, target);
assert(game_at(g, src)->has_monster);
struct field *t = game_at(g, target);
if(t->type == MONSTER) {
attack(game_at(g, src), t);
if(t->has_monster) {
attack(&game_at(g, src)->m, t);
} else {
return move_object(g, src, target);
}
@@ -190,14 +188,14 @@ void run_ai(struct game *g, struct point player)
for(size_t x = 0; x < g->xs; x++)
{
pointarr res;
if(game_at(g, (struct point){y,x})->type == MONSTER && !game_at(g, (struct point){y,x})->u.m.isplayer) {
if(game_at(g, (struct point){y,x})->has_monster && !game_at(g, (struct point){y,x})->m.isplayer) {
unsigned *id;
darray_foreach(id, checked)
{
if(*id == game_at(g, (struct point){y,x})->u.m.id)
if(*id == game_at(g, (struct point){y,x})->m.id)
goto next;
}
darray_append(checked, game_at(g, (struct point){y,x})->u.m.id);
darray_append(checked, game_at(g, (struct point){y,x})->m.id);
res = astar(g, (struct point){y,x}, player, AGGRO_RANGE);
if(res.size >= 2) {
@@ -233,23 +231,20 @@ void loop(struct game *g)
███████║██║ ██║██║ ██║ ██║ ╚████║███████╗╚██████╗██║ ██╗██║ ██║██║ ██║╚██████╔╝███████╗██║ ╚═╝ ██║╚██████╔╝███████╗██║ ╚████║██████╔╝\n\
"
*/
*game_at(g, (struct point){1,1}) = (struct object)
game_at(g, (struct point){1,1})->m = (struct monster)
{
.type = MONSTER,
.symbol = 'P',
.u.m =
{
.id = -1,
.name = "Player",
.max_hp = 20,
.current_hp = 20,
.dmg = 2,
.level = 1,
.xp = 0,
.items = darray_new(),
.isplayer = true
}
.id = -1,
.name = "Player",
.max_hp = 20,
.current_hp = 20,
.dmg = 2,
.level = 1,
.xp = 0,
.items = darray_new(),
.isplayer = true
};
game_at(g, (struct point){1,1})->has_monster = true;
struct point player = {1,1};
@@ -257,11 +252,11 @@ void loop(struct game *g)
{
charclear();
charprint("(づ。◕‿‿◕。)づ");
charprint("Name: %s", game_at(g, player)->u.m.name);
charprint("HP : %u/%u", game_at(g, player)->u.m.current_hp, game_at(g, player)->u.m.max_hp);
charprint("DMG: %u", game_at(g, player)->u.m.dmg);
charprint("LVL: %u", game_at(g, player)->u.m.level);
charprint("XP : %u", game_at(g, player)->u.m.xp);
charprint("Name: %s", game_at(g, player)->m.name);
charprint("HP : %u/%u", game_at(g, player)->m.current_hp, game_at(g, player)->m.max_hp);
charprint("DMG: %u", game_at(g, player)->m.dmg);
charprint("LVL: %u", game_at(g, player)->m.level);
charprint("XP : %u", game_at(g, player)->m.xp);
draw_map(g, player);
struct choice c = get_input();
@@ -287,7 +282,7 @@ void loop(struct game *g)
spawn_enemy(g);
break;
case INVENTORY:
inventory(&game_at(g, player)->u.m);
inventory(&game_at(g, player)->m);
break;
case REDRAW:
setup();
Msrc/tui.c
@@ -239,7 +239,11 @@ void draw_map(const struct game *g, struct point p)
wmove(mapwin, line++, 0);
for(size_t j = startx; j < endx; j++)
{
waddch(mapwin, game_at(g, (struct point){.y = i, .x = j})->symbol);
struct field *f = game_at(g, (struct point){.y = i, .x = j});
if(f->has_monster)
waddch(mapwin, f->m.symbol);
else
waddch(mapwin, f->u->ground.symbol);
}
}
@@ -329,7 +333,7 @@ redraw:;
switch(c)
{
case ' ':
if(f(m, i))
if(m->items.size != 0 && f(m, i))
i = 0;
werase(menu);
goto redraw; //items might have changed, so we redraw the list