added game restart
Minclude/algorithm.h
| @@ -3,6 +3,7 @@ | |||
|---|---|---|---|
| 3 | 3 | #include <stddef.h> | |
| 4 | 4 | #include <game.h> | |
| 5 | 5 | ||
| 6 | + | //creates a game, fills it with walls and empty fields | |
| 6 | 7 | struct game make_maze(size_t y, size_t x); | |
| 7 | 8 | typedef darray(struct point) pointarr; | |
| 8 | 9 | ||
Minclude/game.h
| @@ -141,6 +141,7 @@ struct choice | |||
|---|---|---|---|
| 141 | 141 | }u; | |
| 142 | 142 | }; | |
| 143 | 143 | ||
| 144 | + | //returns a point that is relative to p in the direction d | |
| 144 | 145 | static inline struct point relative(struct point p, enum direction d) | |
| 145 | 146 | { | |
| 146 | 147 | switch(d) | |
| @@ -166,7 +167,8 @@ static inline bool in_bounds(struct game *g, struct point p) | |||
|---|---|---|---|
| 166 | 167 | return false; | |
| 167 | 168 | } | |
| 168 | 169 | ||
| 169 | - | static inline void spawn_enemy(struct game *g) | |
| 170 | + | //randomly puts an enemy in an empty spot on the map | |
| 171 | + | static inline void spawn_enemy(struct game *g) | |
| 170 | 172 | { | |
| 171 | 173 | while(true) | |
| 172 | 174 | { | |
| @@ -179,5 +181,6 @@ static inline void spawn_enemy(struct game *g) | |||
|---|---|---|---|
| 179 | 181 | } | |
| 180 | 182 | } | |
| 181 | 183 | ||
| 184 | + | void loop(); //main game loop | |
| 182 | 185 | ||
| 183 | 186 | #endif | |
Dinclude/loop.h-7
| @@ -1,7 +0,0 @@ | |||
|---|---|---|---|
| 1 | - | #ifndef LOOP_H | |
| 2 | - | #define LOOP_H | |
| 3 | - | ||
| 4 | - | void loop(struct game *g); | |
| 5 | - | ||
| 6 | - | ||
| 7 | - | #endif //LOOP_H | |
Minclude/tui.h
| @@ -6,9 +6,9 @@ | |||
|---|---|---|---|
| 6 | 6 | #include <stddef.h> | |
| 7 | 7 | ||
| 8 | 8 | bool setup(); //setups screens, doesn't redaw contents | |
| 9 | - | void printlog(); | |
| 9 | + | void printlog(); //clears & reprints the log window | |
| 10 | 10 | void logstr(const char *format, ...); //echoes printf string to the logwindow TODO: fix multiline log | |
| 11 | - | void charclear(); | |
| 11 | + | void charclear(); //clears the character screen | |
| 12 | 12 | void charprint(const char *format, ...); //echoes printf string to the charwindow | |
| 13 | 13 | void log_scroll(enum direction d); //scrolls the log up or down | |
| 14 | 14 | void draw_map(const struct game *g, struct point p); //draws the map around the player | |
| @@ -18,8 +18,4 @@ typedef bool(itemselectfn)(struct monster *m, size_t i); //returns true if curso | |||
|---|---|---|---|
| 18 | 18 | void itemselect(struct monster *m, itemselectfn f); //provides an inventory screen, calls f when the space is pressed on an item | |
| 19 | 19 | //TODO: create general select screen | |
| 20 | 20 | ||
| 21 | - | extern size_t logindex; | |
| 22 | - | extern size_t loglength; | |
| 23 | - | extern char **logs; | |
| 24 | - | ||
| 25 | 21 | #endif //TUI_H | |
Msrc/algorithm.c
| @@ -31,10 +31,10 @@ static bool maze_in_bounds(size_t ys, size_t xs, struct point p) | |||
|---|---|---|---|
| 31 | 31 | ||
| 32 | 32 | struct game make_maze(size_t y, size_t x) | |
| 33 | 33 | { | |
| 34 | - | bool yeven = (y%2 == 0); | |
| 35 | - | bool xeven = (x%2 == 0); | |
| 36 | - | y += yeven; //it must be an uneven number to look fine | |
| 37 | - | x += xeven; | |
| 34 | + | assert(y >= 5); | |
| 35 | + | assert(y >= 5); | |
| 36 | + | y += (y%2 == 0); //it must be an uneven number to look fine | |
| 37 | + | x += (x%2 == 0); | |
| 38 | 38 | struct game g = create_game(y, x); | |
| 39 | 39 | ||
| 40 | 40 | char *maze = xmalloc(y * x + 1); | |
Msrc/loop.c
| @@ -14,12 +14,13 @@ | |||
|---|---|---|---|
| 14 | 14 | #include <tui.h> | |
| 15 | 15 | #include <algorithm.h> | |
| 16 | 16 | #include <config.h> | |
| 17 | + | #include <items.h> | |
| 17 | 18 | ||
| 18 | 19 | #define NOOBJ_OBJECT (struct object){.type = NOOBJ, .symbol = ' '} | |
| 19 | 20 | ||
| 20 | 21 | unsigned m_id = 0; | |
| 21 | 22 | ||
| 22 | - | struct choice get_input(void) | |
| 23 | + | static struct choice get_input(void) | |
| 23 | 24 | { | |
| 24 | 25 | struct choice c; | |
| 25 | 26 | ||
| @@ -69,6 +70,7 @@ start:; | |||
|---|---|---|---|
| 69 | 70 | return c; | |
| 70 | 71 | } | |
| 71 | 72 | ||
| 73 | + | //adds xp to m, increases stats and opens a messagebox | |
| 72 | 74 | static void addxp(struct monster *m, unsigned xp) | |
| 73 | 75 | { | |
| 74 | 76 | m->xp += xp; | |
| @@ -83,8 +85,11 @@ static void addxp(struct monster *m, unsigned xp) | |||
|---|---|---|---|
| 83 | 85 | } | |
| 84 | 86 | } | |
| 85 | 87 | ||
| 88 | + | //inflicts src's damage to target, removes targets monster if hp goes to zero | |
| 89 | + | //gives src xp if target is killed | |
| 86 | 90 | static void attack(struct monster *src, struct field *target) | |
| 87 | 91 | { | |
| 92 | + | assert(target->has_monster); | |
| 88 | 93 | if(src->isplayer) | |
| 89 | 94 | logstr("%s hit %s for %d damage", src->name, target->m.name, src->dmg); | |
| 90 | 95 | ||
| @@ -104,6 +109,7 @@ static void attack(struct monster *src, struct field *target) | |||
|---|---|---|---|
| 104 | 109 | } | |
| 105 | 110 | } | |
| 106 | 111 | ||
| 112 | + | //returns true if adding was successful, otherwise false | |
| 107 | 113 | static bool additem(struct monster *m, struct item *it) | |
| 108 | 114 | { | |
| 109 | 115 | darray_append(m->items, *it); | |
| @@ -115,7 +121,9 @@ static void rmvitem(struct monster *m, size_t i) | |||
|---|---|---|---|
| 115 | 121 | darray_remove(m->items, i); | |
| 116 | 122 | } | |
| 117 | 123 | ||
| 118 | - | bool inventorycallback(struct monster *m, size_t i) | |
| 124 | + | //called by itemselect, uses an item if its usable | |
| 125 | + | //equips it and does stat recalculation if its an equip | |
| 126 | + | static bool inventorycallback(struct monster *m, size_t i) | |
| 119 | 127 | { | |
| 120 | 128 | struct item *it = &darray_item(m->items,i); | |
| 121 | 129 | if(it->type == USE) { | |
| @@ -138,16 +146,17 @@ bool inventorycallback(struct monster *m, size_t i) | |||
|---|---|---|---|
| 138 | 146 | return false; | |
| 139 | 147 | } | |
| 140 | 148 | ||
| 141 | - | void inventory(struct monster *m) | |
| 149 | + | static void inventory(struct monster *m) | |
| 142 | 150 | { | |
| 143 | 151 | itemselect(m, inventorycallback); | |
| 144 | 152 | } | |
| 145 | 153 | ||
| 146 | - | ||
| 154 | + | //moves the object in src to target if target is empty | |
| 155 | + | //puts an item in the inventory of src if src is a monster and target contains an item | |
| 147 | 156 | //TODO: player moves on target, create new map | |
| 148 | - | struct point move_object(struct game *g, struct point src, struct point target) | |
| 157 | + | static struct point move_object(struct game *g, struct point src, struct point target) | |
| 149 | 158 | { | |
| 150 | - | if(game_at(g, target)->u->ground.type == NOOBJ && !game_at(g, target)->has_monster) { | |
| 159 | + | if((game_at(g, target)->u->ground.type == NOOBJ || game_at(g, target)->u->ground.type == TARGET) && !game_at(g, target)->has_monster) { | |
| 151 | 160 | game_at(g, target)->has_monster = true; | |
| 152 | 161 | game_at(g, target)->m = game_at(g, src)->m; | |
| 153 | 162 | game_at(g, src)->has_monster = false; | |
| @@ -180,7 +189,7 @@ static inline struct point attack_move(struct game *g, struct point src, struct | |||
|---|---|---|---|
| 180 | 189 | return src; | |
| 181 | 190 | } | |
| 182 | 191 | ||
| 183 | - | void run_ai(struct game *g, struct point player) | |
| 192 | + | static void run_ai(struct game *g, struct point player) | |
| 184 | 193 | { | |
| 185 | 194 | darray(unsigned) checked = darray_new(); | |
| 186 | 195 | for(size_t y = 0; y < g->ys; y++) | |
| @@ -219,19 +228,12 @@ void run_ai(struct game *g, struct point player) | |||
|---|---|---|---|
| 219 | 228 | darray_free(checked); | |
| 220 | 229 | } | |
| 221 | 230 | ||
| 222 | - | ||
| 223 | - | void loop(struct game *g) | |
| 231 | + | //creates game and spawns loot and enemies | |
| 232 | + | static struct game setup_game() | |
| 224 | 233 | { | |
| 225 | - | /* | |
| 226 | - | "\ | |
| 227 | - | ███████╗██████╗ ██╗ ██╗ ███╗ ██╗███████╗ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ ███████╗███╗ ███╗██╗ ██╗███████╗███╗ ██╗██████╗ \n\ | |
| 228 | - | ██╔════╝██╔══██╗██║ ██║ ████╗ ██║██╔════╝██╔════╝██║ ██╔╝██╔══██╗██╔══██╗██╔════╝ ██╔════╝████╗ ████║██║ ██║██╔════╝████╗ ██║██╔══██╗\n\ | |
| 229 | - | ███████╗██████╔╝███████║ ██╔██╗ ██║█████╗ ██║ █████╔╝ ███████║██████╔╝██║ ███╗█████╗ ██╔████╔██║██║ ██║█████╗ ██╔██╗ ██║██║ ██║\n\ | |
| 230 | - | ╚════██║██╔══██╗██╔══██║ ██║╚██╗██║██╔══╝ ██║ ██╔═██╗ ██╔══██║██╔══██╗██║ ██║██╔══╝ ██║╚██╔╝██║██║ ██║██╔══╝ ██║╚██╗██║██║ ██║\n\ | |
| 231 | - | ███████║██║ ██║██║ ██║ ██║ ╚████║███████╗╚██████╗██║ ██╗██║ ██║██║ ██║╚██████╔╝███████╗██║ ╚═╝ ██║╚██████╔╝███████╗██║ ╚████║██████╔╝\n\ | |
| 232 | - | " | |
| 233 | - | */ | |
| 234 | - | game_at(g, (struct point){1,1})->m = (struct monster) | |
| 234 | + | struct game g = make_maze(randrange(GAME_MIN_Y, GAME_MAX_Y), randrange(GAME_MIN_X, GAME_MAX_X)); | |
| 235 | + | ||
| 236 | + | game_at(&g, (struct point){1,1})->m = (struct monster) //TODO: keep player between levels | |
| 235 | 237 | { | |
| 236 | 238 | .symbol = 'P', | |
| 237 | 239 | .id = -1, | |
| @@ -244,7 +246,27 @@ void loop(struct game *g) | |||
|---|---|---|---|
| 244 | 246 | .items = darray_new(), | |
| 245 | 247 | .isplayer = true | |
| 246 | 248 | }; | |
| 247 | - | game_at(g, (struct point){1,1})->has_monster = true; | |
| 249 | + | game_at(&g, (struct point){1,1})->has_monster = true; | |
| 250 | + | ||
| 251 | + | size_t num_enemies = randrange(MIN_ENEMIES, MAX_ENEMIES); | |
| 252 | + | for(size_t i = 0; i < num_enemies; i++) | |
| 253 | + | { | |
| 254 | + | spawn_enemy(&g); | |
| 255 | + | } | |
| 256 | + | ||
| 257 | + | size_t num_items = randrange(MIN_LOOT, MAX_LOOT); | |
| 258 | + | for(size_t i = 0; i < num_items; i++) | |
| 259 | + | { | |
| 260 | + | spawn_item(&g); | |
| 261 | + | } | |
| 262 | + | ||
| 263 | + | return g; | |
| 264 | + | } | |
| 265 | + | ||
| 266 | + | ||
| 267 | + | void loop() | |
| 268 | + | { | |
| 269 | + | struct game g = setup_game(); | |
| 248 | 270 | ||
| 249 | 271 | struct point player = {1,1}; | |
| 250 | 272 | ||
| @@ -252,12 +274,12 @@ void loop(struct game *g) | |||
|---|---|---|---|
| 252 | 274 | { | |
| 253 | 275 | charclear(); | |
| 254 | 276 | charprint("(づ。◕‿‿◕。)づ"); | |
| 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); | |
| 260 | - | draw_map(g, player); | |
| 277 | + | charprint("Name: %s", game_at(&g, player)->m.name); | |
| 278 | + | charprint("HP : %u/%u", game_at(&g, player)->m.current_hp, game_at(&g, player)->m.max_hp); | |
| 279 | + | charprint("DMG: %u", game_at(&g, player)->m.dmg); | |
| 280 | + | charprint("LVL: %u", game_at(&g, player)->m.level); | |
| 281 | + | charprint("XP : %u", game_at(&g, player)->m.xp); | |
| 282 | + | draw_map(&g, player); | |
| 261 | 283 | ||
| 262 | 284 | struct choice c = get_input(); | |
| 263 | 285 | switch(c.a) | |
| @@ -266,23 +288,30 @@ void loop(struct game *g) | |||
|---|---|---|---|
| 266 | 288 | logstr("Invalid input, try again"); | |
| 267 | 289 | continue; | |
| 268 | 290 | case QUIT: | |
| 291 | + | delete_game(&g); | |
| 269 | 292 | return; | |
| 270 | 293 | case MOVE:; | |
| 271 | 294 | struct point targetpos = relative(player, c.u.d); | |
| 272 | 295 | ||
| 273 | - | if(!in_bounds(g, targetpos)) { | |
| 296 | + | if(!in_bounds(&g, targetpos)) { | |
| 274 | 297 | logstr("Target not in bounds"); | |
| 275 | 298 | continue; | |
| 276 | 299 | } | |
| 277 | 300 | ||
| 278 | - | player = attack_move(g, player, targetpos); | |
| 279 | - | run_ai(g, player); | |
| 301 | + | player = attack_move(&g, player, targetpos); | |
| 302 | + | if(game_at(&g, player)->u->ground.type == TARGET) | |
| 303 | + | { | |
| 304 | + | delete_game(&g); | |
| 305 | + | loop(); | |
| 306 | + | return; | |
| 307 | + | } | |
| 308 | + | run_ai(&g, player); | |
| 280 | 309 | break; | |
| 281 | 310 | case SPAWN: | |
| 282 | - | spawn_enemy(g); | |
| 311 | + | spawn_enemy(&g); | |
| 283 | 312 | break; | |
| 284 | 313 | case INVENTORY: | |
| 285 | - | inventory(&game_at(g, player)->m); | |
| 314 | + | inventory(&game_at(&g, player)->m); | |
| 286 | 315 | break; | |
| 287 | 316 | case REDRAW: | |
| 288 | 317 | setup(); | |
Msrc/main.c
| @@ -7,18 +7,11 @@ | |||
|---|---|---|---|
| 7 | 7 | #include <locale.h> | |
| 8 | 8 | #include <time.h> | |
| 9 | 9 | ||
| 10 | - | ||
| 11 | - | #include <helper.h> | |
| 12 | 10 | #include <tui.h> | |
| 13 | - | #include <loop.h> | |
| 14 | 11 | #include <game.h> | |
| 15 | - | #include <algorithm.h> | |
| 16 | - | #include <config.h> | |
| 17 | - | #include <items.h> | |
| 18 | - | ||
| 19 | - | ||
| 20 | 12 | ||
| 21 | 13 | #include <unistd.h> | |
| 14 | + | ||
| 22 | 15 | int main() | |
| 23 | 16 | { | |
| 24 | 17 | srand(time(NULL)); | |
| @@ -26,20 +19,7 @@ int main() | |||
|---|---|---|---|
| 26 | 19 | setup(); | |
| 27 | 20 | logstr("Game started"); | |
| 28 | 21 | ||
| 29 | - | struct game g = make_maze(randrange(GAME_MIN_Y, GAME_MAX_Y), randrange(GAME_MIN_X, GAME_MAX_X)); | |
| 30 | - | size_t num_enemies = randrange(MIN_ENEMIES, MAX_ENEMIES); | |
| 31 | - | for(size_t i = 0; i < num_enemies; i++) | |
| 32 | - | { | |
| 33 | - | spawn_enemy(&g); | |
| 34 | - | } | |
| 35 | - | ||
| 36 | - | size_t num_items = randrange(MIN_LOOT, MAX_LOOT); | |
| 37 | - | for(size_t i = 0; i < num_items; i++) | |
| 38 | - | { | |
| 39 | - | spawn_item(&g); | |
| 40 | - | } | |
| 41 | - | ||
| 42 | - | loop(&g); | |
| 43 | - | ||
| 44 | - | delete_game(&g); | |
| 22 | + | ||
| 23 | + | loop(); | |
| 24 | + | ||
| 45 | 25 | } | |