added layered map, fixed item select with 0 items

AuthorKonata <konata@posteo.jp>
Date
Commitdf62e721840b6ae890f39e6ab76a892fcd033835
Parent5bfdefc
5 files changed, 121 insertions(+), 120 deletions(-)
Minclude/game.h
@@ -5,7 +5,28 @@
55 #include <assert.h>
66 #include <helper.h>
77 #include <darray.h>
8-#define MAXITEMS 10
8+
9+#define MAX(x,y) (x >= y ? x : y)
10+#define MIN(x,y) (x <= y ? x : y)
11+
12+#define ORC (struct monster)\
13+ {\
14+ .symbol = 'O',\
15+ .name = "Zog Zog", \
16+ .id = m_id++, .current_hp = 10, .max_hp = 10, .dmg = 1,\
17+ .level = 5 , .xp = 0, .items = darray_new(), .isplayer = false\
18+ }
19+
20+#define EMPTYFIELD (struct object)\
21+ {\
22+ .type = NOOBJ,\
23+ .symbol = ' ',\
24+ }
25+#define WALLFIELD (struct object)\
26+ {\
27+ .type = WALL,\
28+ .symbol = '#',\
29+ }
930
1031 extern unsigned m_id;
1132
@@ -24,8 +45,15 @@ struct use
2445 unsigned restorehp;
2546 };
2647
48+struct object
49+{
50+ enum objtype type;
51+ char symbol;
52+};
53+
2754 struct item
2855 {
56+ struct object o;
2957 const char *name;
3058 enum itemtype type;
3159 union
@@ -38,6 +66,7 @@ struct item
3866
3967 struct monster
4068 {
69+ char symbol;
4170 const char *name;
4271 unsigned id;
4372 unsigned current_hp;
@@ -49,44 +78,37 @@ struct monster
4978 bool isplayer;
5079 };
5180
52-static inline size_t item_len(const struct monster *m)
81+struct field
5382 {
54- for(size_t i = 0; i < MAXITEMS; i++)
55- {
56- if(darray_item(m->items, i).type == NOITEM)
57- return i;
58- }
59- return MAXITEMS;
60-}
61-
62-
63-struct object
64-{
65- enum objtype type;
66- char symbol;
6783 union
6884 {
69- struct monster m;
70- struct item i;
71- } u;
85+ struct object ground;
86+ struct item it;
87+ } *u;
88+ struct monster m;
89+ bool has_monster;
7290 };
7391
7492 struct game
7593 {
76- struct object *map;
94+ struct field *map;
7795 size_t xs, ys;
7896 };
7997
80-static inline struct object *game_at(const struct game *g, struct point p)
98+static inline struct field *game_at(const struct game *g, struct point p)
8199 {
82100 return &g->map[p.y * g->xs + p.x];
83101 }
84102
85-
86103 static inline struct game create_game(size_t y, size_t x)
87104 {
88105 struct game ret;
89- ret.map = xmalloc(x * y * sizeof * ret.map);
106+ ret.map = xmalloc(x * y * sizeof(*ret.map));
107+ for(size_t i = 0; i < x*y; i++)
108+ {
109+ ret.map[i].u = xmalloc(sizeof(*ret.map[i].u));
110+ ret.map[i].has_monster = false;
111+ }
90112 ret.xs = x;
91113 ret.ys = y;
92114
@@ -99,8 +121,9 @@ static inline void delete_game(struct game *g)
99121 {
100122 for(size_t x = 0; x < g->xs; x++)
101123 {
102- if(game_at(g, (struct point){y,x})->type == MONSTER)
103- darray_free(game_at(g, (struct point){y,x})->u.m.items);
124+ if(game_at(g, (struct point){y,x})->has_monster)
125+ darray_free(game_at(g, (struct point){y,x})->m.items);
126+ free(game_at(g, (struct point){y,x})->u);
104127 }
105128 }
106129 free(g->map);
@@ -118,27 +141,6 @@ struct choice
118141 }u;
119142 };
120143
121-#define MAX(x,y) (x >= y ? x : y)
122-#define MIN(x,y) (x <= y ? x : y)
123-
124-#define ORC (struct object)\
125- {\
126- .type = MONSTER,\
127- .symbol = 'O',\
128- .u.m = {"Zog Zog", m_id++, 10, 10, 1, 5 , 0, darray_new(), false}\
129- }
130-
131-#define EMPTYFIELD (struct object)\
132- {\
133- .type = NOOBJ,\
134- .symbol = ' ',\
135- }
136-#define WALLFIELD (struct object)\
137- {\
138- .type = WALL,\
139- .symbol = '#',\
140- }
141-
142144 static inline struct point relative(struct point p, enum direction d)
143145 {
144146 switch(d)
@@ -169,8 +171,9 @@ static inline void spawn_enemy(struct game *g)
169171 while(true)
170172 {
171173 struct point p = {randrange(0, g->ys), randrange(0, g->xs)};
172- if(in_bounds(g, p) && game_at(g, p)->type == NOOBJ) {
173- *game_at(g, p) = ORC;
174+ if(in_bounds(g, p) && game_at(g, p)->u->ground.type != WALL && !game_at(g, p)->has_monster) {
175+ game_at(g, p)->m = ORC;
176+ game_at(g, p)->has_monster = true;
174177 break;
175178 }
176179 }
Minclude/items.h
@@ -10,11 +10,11 @@
1010 .u.i = {"Dagger of Darkness", EQUIP, {{0, 2, 0}}}\
1111 };
1212
13-#define HP_POTION (struct object)\
13+#define HP_POTION (struct item)\
1414 {\
15- .type = ITEM,\
16- .symbol = 'p',\
17- .u.i = {"HP Potion", USE, {{5, 0, 0}}}\
15+ .o.type = ITEM,\
16+ .o.symbol = 'p',\
17+ .name = "HP Potion", .type = USE, .u = {.u.restorehp = 10}\
1818 };
1919
2020 static inline void spawn_item(struct game *g)
@@ -22,8 +22,8 @@ static inline void spawn_item(struct game *g)
2222 while(true)
2323 {
2424 struct point p = {randrange(0, g->ys), randrange(0, g->xs)};
25- if(in_bounds(g, p) && game_at(g, p)->type == NOOBJ) {
26- *game_at(g, p) = HP_POTION;
25+ if(in_bounds(g, p) && game_at(g, p)->u->ground.type == NOOBJ) {
26+ game_at(g, p)->u->it = HP_POTION;
2727 break;
2828 }
2929 }
Msrc/algorithm.c
@@ -14,8 +14,7 @@
1414
1515 #define UNVISITED '#'
1616 #define VISITED ' '
17-#define WALL '#'
18-#define NOWALL ' '
17+
1918
2019 typedef unsigned long size_t;
2120
@@ -39,7 +38,7 @@ struct game make_maze(size_t y, size_t x)
3938 struct game g = create_game(y, x);
4039
4140 char *maze = xmalloc(y * x + 1);
42- memset(maze, WALL, y * x);
41+ memset(maze, UNVISITED, y * x);
4342 maze[y * x] = '\0';
4443 darray(struct point) stack = darray_new();
4544
@@ -69,7 +68,7 @@ struct game make_maze(size_t y, size_t x)
6968
7069 struct point choice = unindexpoint(nb[c]);
7170 struct point diff = {choice.y-current.y, choice.x-current.x};
72- *maze_at(maze, x, (struct point){index(current.y)+diff.y, index(current.x)+diff.x}) = NOWALL;
71+ *maze_at(maze, x, (struct point){index(current.y)+diff.y, index(current.x)+diff.x}) = VISITED;
7372 current = choice;
7473 } else if(!darray_empty(stack)) {
7574 current = darray_pop(stack);
@@ -82,15 +81,15 @@ struct game make_maze(size_t y, size_t x)
8281 {
8382 for(size_t j = 0; j < x; j++)
8483 {
85- if(*maze_at(maze, x, (struct point){i,j}) == NOWALL)
86- *game_at(&g, (struct point){i,j}) = EMPTYFIELD;
84+ if(*maze_at(maze, x, (struct point){i,j}) == VISITED)
85+ game_at(&g, (struct point){i,j})->u->ground = EMPTYFIELD;
8786 else
88- *game_at(&g, (struct point){i,j}) = WALLFIELD;
87+ game_at(&g, (struct point){i,j})->u->ground = WALLFIELD;
8988 }
9089 }
9190
92- game_at(&g, (struct point){y-2,x-2})->symbol = '*';
93- game_at(&g, (struct point){y-2,x-2})->type = TARGET;
91+ game_at(&g, (struct point){y-2,x-2})->u->ground.symbol = '*';
92+ game_at(&g, (struct point){y-2,x-2})->u->ground.type = TARGET;
9493
9594 darray_free(stack);
9695 free(maze);
@@ -149,13 +148,13 @@ pointarr astar(struct game *g, struct point start, struct point target, size_t m
149148 struct point left = (struct point){currentnode->p.y, currentnode->p.x-1};
150149 struct point right = (struct point){currentnode->p.y, currentnode->p.x+1};
151150
152- if(game_at(g,left)->type == NOOBJ || game_at(g,left)->type == MONSTER)
151+ if(game_at(g,left)->u->ground.type == NOOBJ)
153152 darray_append(children, left);
154- if(game_at(g,right)->type == NOOBJ || game_at(g,right)->type == MONSTER)
153+ if(game_at(g,right)->u->ground.type == NOOBJ)
155154 darray_append(children, right);
156- if(game_at(g,up)->type == NOOBJ || game_at(g,up)->type == MONSTER)
155+ if(game_at(g,up)->u->ground.type == NOOBJ)
157156 darray_append(children, up);
158- if(game_at(g,down)->type == NOOBJ || game_at(g,down)->type == MONSTER)
157+ if(game_at(g,down)->u->ground.type == NOOBJ)
159158 darray_append(children, down);
160159
161160
Msrc/loop.c
@@ -83,30 +83,24 @@ static void addxp(struct monster *m, unsigned xp)
8383 }
8484 }
8585
86-static void attack(struct object *src, struct object *target)
86+static void attack(struct monster *src, struct field *target)
8787 {
88- assert(src->type == MONSTER);
88+ if(src->isplayer)
89+ logstr("%s hit %s for %d damage", src->name, target->m.name, src->dmg);
90+
91+ if(src->dmg >= target->m.current_hp) {
92+ logstr("%s killed %s", src->name ,target->m.name);
8993
90- if(target->type == MONSTER) {
91- if(src->u.m.isplayer)
92- logstr("%s hit %s for %d damage", src->u.m.name, target->u.m.name, src->u.m.dmg);
93-
94- if(src->u.m.dmg >= target->u.m.current_hp) {
95- logstr("%s killed %s", src->u.m.name ,target->u.m.name);
96-
97- if(src->u.m.isplayer) {
98- addxp(&src->u.m, target->u.m.level*10);
99- } else {
100- messagebox("U done did dedden", 1, 0);
101- exit(0);
102- }
103- darray_free(target->u.m.items);
104- *target = NOOBJ_OBJECT;
94+ if(src->isplayer) {
95+ addxp(src, target->m.level*10);
10596 } else {
106- target->u.m.current_hp -= src->u.m.dmg;
97+ messagebox("U done did dedden", 1, 0);
98+ exit(0);
10799 }
100+ darray_free(target->m.items);
101+ target->has_monster = false;
108102 } else {
109- logstr("Target is not a monster or player");
103+ target->m.current_hp -= src->dmg;
110104 }
111105 }
112106
@@ -153,17 +147,20 @@ void inventory(struct monster *m)
153147 //TODO: player moves on target, create new map
154148 struct point move_object(struct game *g, struct point src, struct point target)
155149 {
156- if(game_at(g, target)->type == NOOBJ) {
157- *game_at(g, target) = *game_at(g, src);
158- *game_at(g, src) = NOOBJ_OBJECT;
150+ if(game_at(g, target)->u->ground.type == NOOBJ && !game_at(g, target)->has_monster) {
151+ game_at(g, target)->has_monster = true;
152+ game_at(g, target)->m = game_at(g, src)->m;
153+ game_at(g, src)->has_monster = false;
159154 return target;
160- } else if(game_at(g, target)->type == ITEM && game_at(g, src)->type == MONSTER) {
161- if(!additem(&game_at(g, src)->u.m, &game_at(g, target)->u.i)) {
155+ } else if(game_at(g, target)->u->ground.type == ITEM && !game_at(g, target)->has_monster && game_at(g, src)->has_monster) {
156+ if(!additem(&game_at(g, src)->m, &game_at(g, target)->u->it)) {
162157 logstr("Inventory is full");
163158 return src;
164159 }
165- *game_at(g, target) = *game_at(g, src);
166- *game_at(g, src) = NOOBJ_OBJECT;
160+ game_at(g, target)->has_monster = true;
161+ game_at(g, target)->m = game_at(g, src)->m;
162+ game_at(g, target)->u->ground = EMPTYFIELD;
163+ game_at(g, src)->has_monster = false;
167164 return target;
168165 } else {
169166 return src;
@@ -172,10 +169,11 @@ struct point move_object(struct game *g, struct point src, struct point target)
172169
173170 static inline struct point attack_move(struct game *g, struct point src, struct point target)
174171 {
175- struct object *t = game_at(g, target);
172+ assert(game_at(g, src)->has_monster);
173+ struct field *t = game_at(g, target);
176174
177- if(t->type == MONSTER) {
178- attack(game_at(g, src), t);
175+ if(t->has_monster) {
176+ attack(&game_at(g, src)->m, t);
179177 } else {
180178 return move_object(g, src, target);
181179 }
@@ -190,14 +188,14 @@ void run_ai(struct game *g, struct point player)
190188 for(size_t x = 0; x < g->xs; x++)
191189 {
192190 pointarr res;
193- if(game_at(g, (struct point){y,x})->type == MONSTER && !game_at(g, (struct point){y,x})->u.m.isplayer) {
191+ if(game_at(g, (struct point){y,x})->has_monster && !game_at(g, (struct point){y,x})->m.isplayer) {
194192 unsigned *id;
195193 darray_foreach(id, checked)
196194 {
197- if(*id == game_at(g, (struct point){y,x})->u.m.id)
195+ if(*id == game_at(g, (struct point){y,x})->m.id)
198196 goto next;
199197 }
200- darray_append(checked, game_at(g, (struct point){y,x})->u.m.id);
198+ darray_append(checked, game_at(g, (struct point){y,x})->m.id);
201199
202200 res = astar(g, (struct point){y,x}, player, AGGRO_RANGE);
203201 if(res.size >= 2) {
@@ -233,23 +231,20 @@ void loop(struct game *g)
233231 ███████║██║ ██║██║ ██║ ██║ ╚████║███████╗╚██████╗██║ ██╗██║ ██║██║ ██║╚██████╔╝███████╗██║ ╚═╝ ██║╚██████╔╝███████╗██║ ╚████║██████╔╝\n\
234232 "
235233 */
236- *game_at(g, (struct point){1,1}) = (struct object)
234+ game_at(g, (struct point){1,1})->m = (struct monster)
237235 {
238- .type = MONSTER,
239236 .symbol = 'P',
240- .u.m =
241- {
242- .id = -1,
243- .name = "Player",
244- .max_hp = 20,
245- .current_hp = 20,
246- .dmg = 2,
247- .level = 1,
248- .xp = 0,
249- .items = darray_new(),
250- .isplayer = true
251- }
237+ .id = -1,
238+ .name = "Player",
239+ .max_hp = 20,
240+ .current_hp = 20,
241+ .dmg = 2,
242+ .level = 1,
243+ .xp = 0,
244+ .items = darray_new(),
245+ .isplayer = true
252246 };
247+ game_at(g, (struct point){1,1})->has_monster = true;
253248
254249 struct point player = {1,1};
255250
@@ -257,11 +252,11 @@ void loop(struct game *g)
257252 {
258253 charclear();
259254 charprint("(づ。◕‿‿◕。)づ");
260- charprint("Name: %s", game_at(g, player)->u.m.name);
261- charprint("HP : %u/%u", game_at(g, player)->u.m.current_hp, game_at(g, player)->u.m.max_hp);
262- charprint("DMG: %u", game_at(g, player)->u.m.dmg);
263- charprint("LVL: %u", game_at(g, player)->u.m.level);
264- charprint("XP : %u", game_at(g, player)->u.m.xp);
255+ charprint("Name: %s", game_at(g, player)->m.name);
256+ charprint("HP : %u/%u", game_at(g, player)->m.current_hp, game_at(g, player)->m.max_hp);
257+ charprint("DMG: %u", game_at(g, player)->m.dmg);
258+ charprint("LVL: %u", game_at(g, player)->m.level);
259+ charprint("XP : %u", game_at(g, player)->m.xp);
265260 draw_map(g, player);
266261
267262 struct choice c = get_input();
@@ -287,7 +282,7 @@ void loop(struct game *g)
287282 spawn_enemy(g);
288283 break;
289284 case INVENTORY:
290- inventory(&game_at(g, player)->u.m);
285+ inventory(&game_at(g, player)->m);
291286 break;
292287 case REDRAW:
293288 setup();
Msrc/tui.c
@@ -239,7 +239,11 @@ void draw_map(const struct game *g, struct point p)
239239 wmove(mapwin, line++, 0);
240240 for(size_t j = startx; j < endx; j++)
241241 {
242- waddch(mapwin, game_at(g, (struct point){.y = i, .x = j})->symbol);
242+ struct field *f = game_at(g, (struct point){.y = i, .x = j});
243+ if(f->has_monster)
244+ waddch(mapwin, f->m.symbol);
245+ else
246+ waddch(mapwin, f->u->ground.symbol);
243247 }
244248 }
245249
@@ -329,7 +333,7 @@ redraw:;
329333 switch(c)
330334 {
331335 case ' ':
332- if(f(m, i))
336+ if(m->items.size != 0 && f(m, i))
333337 i = 0;
334338 werase(menu);
335339 goto redraw; //items might have changed, so we redraw the list