From 8adb91a7c7de0716ce55784322e239415bf06e06 Mon Sep 17 00:00:00 2001 From: Christian Heller Date: Fri, 5 Jul 2013 01:26:55 +0200 Subject: [PATCH] Restructured chained objects on map via new ChainMapObject struct, allowing for great refactoring of / duplication elimination on lots of code. --- src/draw_wins.c | 36 ++++----- src/objects_on_map.c | 18 ++--- src/objects_on_map.h | 11 +-- src/roguelike.c | 174 ++++++++++++++++++++++--------------------- src/roguelike.h | 10 +++ 5 files changed, 133 insertions(+), 116 deletions(-) diff --git a/src/draw_wins.c b/src/draw_wins.c index 9c53810..197b7c3 100644 --- a/src/draw_wins.c +++ b/src/draw_wins.c @@ -8,7 +8,9 @@ #include "keybindings.h" #include "objects_on_map.h" -void draw_with_linebreaks (struct Win * win, char * text, uint16_t start_y) { +static void draw_map_objects (void *, struct Map *, struct Win *); + +extern void draw_with_linebreaks (struct Win * win, char * text, uint16_t start_y) { // Write text into window content space. Start on row start_y. Fill unused rows with whitespace. uint16_t x, y; char toggle; @@ -32,7 +34,7 @@ void draw_with_linebreaks (struct Win * win, char * text, uint16_t start_y) { toggle = 1; fin = 1; } } } } } -void draw_text_from_bottom (struct Win * win, char * text) { +extern void draw_text_from_bottom (struct Win * win, char * text) { // Draw text from end/bottom to the top. char toggle = 0; uint16_t x, y, offset; @@ -65,18 +67,24 @@ void draw_text_from_bottom (struct Win * win, char * text) { text = text + (sizeof(char) * (z + 1)); } draw_with_linebreaks(win, text, start_y); } -void draw_log_win (struct Win * win) { +extern void draw_log_win (struct Win * win) { // Draw log text from world struct in win->data from bottom to top. struct World * world = (struct World *) win->data; draw_text_from_bottom(win, world->log); } -void draw_map_win (struct Win * win) { -// Draw map determined by win->data Map struct into window. Respect offset. +static void draw_map_objects (void * start, struct Map * map, struct Win * win) { +// Draw onto map in win the objects in the chain at start. + struct ChainMapObject * cmo; + for (cmo = start; cmo != 0; cmo = cmo->next) + if ( cmo->pos.y >= map->offset.y && cmo->pos.y < map->offset.y + win->frame.size.y + && cmo->pos.x >= map->offset.x && cmo->pos.x < map->offset.x + win->frame.size.x) + mvwaddch(win->frame.curses_win, cmo->pos.y - map->offset.y, cmo->pos.x - map->offset.x, cmo->name); } + +extern void draw_map_win (struct Win * win) { +// Draw map determined by map (from win->data) and various actors/objects into window. Respect scroll offset. struct World * world = (struct World *) win->data; struct Map * map = world->map; struct Player * player = world->player; - struct Monster * monster; - struct Item * item; char * cells = map->cells; uint16_t width_map_av = map->size.x - map->offset.x; uint16_t height_map_av = map->size.y - map->offset.y; @@ -87,19 +95,13 @@ void draw_map_win (struct Win * win) { if (y < height_map_av && x < width_map_av) { mvwaddch(win->frame.curses_win, y, x, cells[z]); z++; } } } - for (item = world->item; item != 0; item = item->next) - if ( item->pos.y >= map->offset.y && item->pos.y < map->offset.y + win->frame.size.y - && item->pos.x >= map->offset.x && item->pos.x < map->offset.x + win->frame.size.x) - mvwaddch(win->frame.curses_win, item->pos.y - map->offset.y, item->pos.x - map->offset.x, item->name); - for (monster = world->monster; monster != 0; monster = monster->next) - if ( monster->pos.y >= map->offset.y && monster->pos.y < map->offset.y + win->frame.size.y - && monster->pos.x >= map->offset.x && monster->pos.x < map->offset.x + win->frame.size.x) - mvwaddch(win->frame.curses_win, monster->pos.y - map->offset.y, monster->pos.x - map->offset.x, monster->name); + draw_map_objects (world->item, map, win); + draw_map_objects (world->monster, map, win); if ( player->pos.y >= map->offset.y && player->pos.y < map->offset.y + win->frame.size.y && player->pos.x >= map->offset.x && player->pos.x < map->offset.x + win->frame.size.x) mvwaddch(win->frame.curses_win, player->pos.y - map->offset.y, player->pos.x - map->offset.x, '@'); } -void draw_info_win (struct Win * win) { +extern void draw_info_win (struct Win * win) { // Draw info window by appending win->data integer value to "Turn: " display. struct World * world = (struct World *) win->data; uint16_t count = world->turn; @@ -107,7 +109,7 @@ void draw_info_win (struct Win * win) { snprintf(text, 100, "Turn: %d", count); draw_with_linebreaks(win, text, 0); } -void draw_keys_win (struct Win * win) { +extern void draw_keys_win (struct Win * win) { // Draw keybindings window. struct World * world = (struct World *) win->data; uint16_t offset = 0, y, x; diff --git a/src/objects_on_map.c b/src/objects_on_map.c index 61efcde..f779b5f 100644 --- a/src/objects_on_map.c +++ b/src/objects_on_map.c @@ -23,36 +23,36 @@ extern struct yx_uint16 find_passable_pos (struct Map * map) { extern void move_monster (struct World * world, struct Monster * monster) { // Move monster in random direction, trigger fighting when hindered by player/monster. char d = rrand(0, 0) % 5; - struct yx_uint16 t = mv_yx_in_dir (d, monster->pos); + struct yx_uint16 t = mv_yx_in_dir (d, monster->cmo.pos); if (yx_uint16_cmp (t, world->player->pos)) { update_log (world, "\nThe monster hits you."); return; } struct Monster * other_monster; - for (other_monster = world->monster; other_monster != 0; other_monster = other_monster->next) { + for (other_monster = world->monster; other_monster != 0; other_monster = other_monster->cmo.next) { if (other_monster == monster) continue; - if (yx_uint16_cmp (t, other_monster->pos)) { + if (yx_uint16_cmp (t, other_monster->cmo.pos)) { update_log (world, "\nMonster bumps into monster."); return; } } if (is_passable(world->map, t)) - monster->pos = t; } + monster->cmo.pos = t; } extern void move_player (struct World * world, char d) { // Move player in direction d, update log and turn over to the enemy. struct yx_uint16 t = mv_yx_in_dir (d, world->player->pos); struct Monster * monster; - for (monster = world->monster; monster != 0; monster = monster->next) - if (yx_uint16_cmp (t, monster->pos)) { + for (monster = world->monster; monster != 0; monster = monster->cmo.next) + if (yx_uint16_cmp (t, monster->cmo.pos)) { update_log (world, "\nYou hit the monster."); monster->hitpoints--; if (0 == monster->hitpoints) { update_log (world, "\nYou kill the monster."); if (world->monster == monster) - world->monster = world->monster->next; + world->monster = world->monster->cmo.next; else { struct Monster * m_prev; - for (m_prev = world->monster; m_prev->next != monster; m_prev = m_prev->next); - m_prev->next = monster->next; } + for (m_prev = world->monster; m_prev->cmo.next != monster; m_prev = m_prev->cmo.next); + m_prev->cmo.next = monster->cmo.next; } free(monster); } turn_over (world, d); return; } diff --git a/src/objects_on_map.h b/src/objects_on_map.h index ccb9bcd..e9c7c65 100644 --- a/src/objects_on_map.h +++ b/src/objects_on_map.h @@ -9,15 +9,16 @@ struct Map; struct Player { struct yx_uint16 pos; }; -struct Item { - struct Item * next; +struct ChainMapObject { + void * next; unsigned char name; struct yx_uint16 pos; }; +struct Item { + struct ChainMapObject cmo; }; + struct Monster { - struct Monster * next; - unsigned char name; - struct yx_uint16 pos; + struct ChainMapObject cmo; unsigned char hitpoints; }; extern char is_passable (struct Map *, struct yx_uint16); diff --git a/src/roguelike.c b/src/roguelike.c index 7cc50d6..0431a10 100644 --- a/src/roguelike.c +++ b/src/roguelike.c @@ -86,7 +86,7 @@ void turn_over (struct World * world, char action) { world->turn++; rrand(1, world->seed * world->turn); struct Monster * monster; - for (monster = world->monster; monster != 0; monster = monster->next) + for (monster = world->monster; monster != 0; monster = monster->cmo.next) move_monster(world, monster); } void save_game(struct World * world) { @@ -96,19 +96,8 @@ void save_game(struct World * world) { write_uint32_bigendian(world->turn, file); write_uint16_bigendian(world->player->pos.y + 1, file); write_uint16_bigendian(world->player->pos.x + 1, file); - struct Monster * monster; - for (monster = world->monster; monster != 0; monster = monster->next) { - write_uint16_bigendian(monster->pos.y + 1, file); - write_uint16_bigendian(monster->pos.x + 1, file); - fputc(monster->name, file); - fputc(monster->hitpoints, file); } - write_uint16_bigendian(0, file); - struct Item * item; - for (item = world->item; item != 0; item = item->next) { - write_uint16_bigendian(item->pos.y + 1, file); - write_uint16_bigendian(item->pos.x + 1, file); - fputc(item->name, file); } - write_uint16_bigendian(0, file); + write_map_objects (world->monster, file, write_map_objects_monsterdata); + write_map_objects (world->item, file, readwrite_map_objects_dummy); fclose(file); } void toggle_window (struct WinMeta * win_meta, struct Win * win) { @@ -186,6 +175,88 @@ unsigned char meta_keys(int key, struct World * world, struct WinMeta * win_meta map_scroll (world->map, WEST); return 0; } +void write_map_objects_monsterdata (void * start, FILE * file) { +// Write to file data specific tto map objects of type monster. + struct Monster * monster = (struct Monster *) start; + fputc(monster->hitpoints, file); } + +void readwrite_map_objects_dummy (void * dummy, FILE * file) { +// Dummy function for calls of (write|read)_map_objects on map objects without specific attributes. + ; } + +void write_map_objects (void * start, FILE * file, void (* f) (void *, FILE *) ) { +// Write into file the map object chain starting at start, use f() for object-type specific data. + struct ChainMapObject * cmo; + for (cmo = start; cmo != 0; cmo = cmo->next) { + write_uint16_bigendian(cmo->pos.y + 1, file); + write_uint16_bigendian(cmo->pos.x + 1, file); + fputc(cmo->name, file); + f (cmo, file); } + write_uint16_bigendian(0, file); } + +void read_map_objects_monsterdata (void * start, FILE * file) { +// Read from file data speciifc to map objects of type monster. + struct Monster * monster = (struct Monster *) start; + monster->hitpoints = fgetc(file); } + +void read_map_objects (void * start, FILE * file, size_t size, void (* f) (void *, FILE *) ) { +// Read from file chain of map objects starting at start, use f() for object-type specific data. + int * q = start; + * q = 0; + struct ChainMapObject * cmo; + struct ChainMapObject * * z = start; + uint16_t test; + char still_at_start = 1; + while (1) { + test = read_uint16_bigendian(file); + if (0 == test) + break; + if (still_at_start) { + cmo = malloc(size); + * z = cmo; + still_at_start = 0; } + else { + cmo->next = malloc(size); + cmo = cmo->next; } + cmo->pos.y = test - 1; + cmo->pos.x = read_uint16_bigendian(file) - 1; + cmo->name = fgetc(file); + f (cmo, file); } + if (!still_at_start) + cmo->next = 0; } + +void build_map_objects_monsterdata (void * start) { +// Build data specific to map objects of type monster. + struct Monster * monster = (struct Monster *) start; + monster->cmo.name = 'A' + (rrand(0, 0) % 8); + monster->hitpoints = 5; } + +void build_map_objects_itemdata (void * start) { +// Build data speciifc to map objects of type data. + struct Item * item = (struct Item *) start; + item->cmo.name = '#' + (rrand(0, 0) % 4); } + +void build_map_objects (void * start, unsigned char n, size_t size, void (* f) (void *), struct Map * map) { +// Build chain of n map objects starting at start, use f() for object-specific data. + int * q = start; + * q = 0; + unsigned char i; + struct ChainMapObject * cmo; + struct ChainMapObject * * z = start; + char still_at_start = 1; + for (i = 0; i < n; i++) { + if (still_at_start) { + cmo = malloc(size); + * z = cmo; + still_at_start = 0; } + else { + cmo->next = malloc(size); + cmo = cmo->next; } + cmo->pos = find_passable_pos(map); + f(cmo); } + if (!still_at_start) + cmo->next = 0; } + int main (int argc, char *argv[]) { struct World world; @@ -209,10 +280,6 @@ int main (int argc, char *argv[]) { update_log (&world, " "); struct Player player; world.player = &player; - struct Monster * monster; - struct Item * item; - uint16_t test; - char start; // For interactive mode, try to load world state from savefile. FILE * file; @@ -222,43 +289,8 @@ int main (int argc, char *argv[]) { world.turn = read_uint32_bigendian(file); player.pos.y = read_uint16_bigendian(file) - 1; player.pos.x = read_uint16_bigendian(file) - 1; - start = 1; - world.monster = 0; - while (1) { - test = read_uint16_bigendian(file); - if (0 == test) - break; - if (start) { - monster = malloc(sizeof(struct Monster)); - world.monster = monster; - start = 0; } - else { - monster->next = malloc(sizeof(struct Monster)); - monster = monster->next; } - monster->pos.y = test - 1; - monster->pos.x = read_uint16_bigendian(file) - 1; - monster->name = fgetc(file); - monster->hitpoints = fgetc(file); } - if (!start) - monster->next = 0; - start = 1; - world.item = 0; - while (1) { - test = read_uint16_bigendian(file); - if (0 == test) - break; - if (start) { - item = malloc(sizeof(struct Item)); - world.item = item; - start = 0; } - else { - item->next = malloc(sizeof(struct Item)); - item = item->next; } - item->pos.y = test - 1; - item->pos.x = read_uint16_bigendian(file) - 1; - item->name = fgetc(file); } - if (!start) - item->next = 0; + read_map_objects (&world.monster, file, sizeof(struct Monster), read_map_objects_monsterdata); + read_map_objects (&world.item, file, sizeof(struct Item), readwrite_map_objects_dummy); fclose(file); } // For non-interactive mode, try to load world state from record file. @@ -283,36 +315,8 @@ int main (int argc, char *argv[]) { player.pos = find_passable_pos(&map); unsigned char n_monsters = rrand(0, 0) % 16; unsigned char n_items = rrand(0, 0) % 48; - unsigned char i; - start = 1; - world.monster = 0; - for (i = 0; i < n_monsters; i++) { - if (start) { - monster = malloc(sizeof(struct Monster)); - world.monster = monster; - start = 0; } - else { - monster->next = malloc(sizeof(struct Monster)); - monster = monster->next; } - monster->pos = find_passable_pos(&map); - monster->name = 'A' + (rrand(0, 0) % 8); - monster->hitpoints = 5; } - if (!start) - monster->next = 0; - start = 1; - world.item = 0; - for (i = 0; i < n_items; i++) { - if (start) { - item = malloc(sizeof(struct Item)); - world.item = item; - start = 0; } - else { - item->next = malloc(sizeof(struct Item)); - item = item->next; } - item->pos = find_passable_pos(&map); - item->name = '#' + (rrand(0, 0) % 4); } - if (!start) - item->next = 0; } + build_map_objects (&world.monster, n_monsters, sizeof(struct Monster), build_map_objects_monsterdata, &map); + build_map_objects (&world.item, n_items, sizeof(struct Item), build_map_objects_itemdata, &map); } // Initialize window system and windows. WINDOW * screen = initscr(); diff --git a/src/roguelike.h b/src/roguelike.h index 14ca783..a933362 100644 --- a/src/roguelike.h +++ b/src/roguelike.h @@ -1,6 +1,7 @@ #ifndef ROGUELIKE_H #define ROGUELIKE_H +#include #include #include "yx_uint16.h" @@ -41,4 +42,13 @@ extern void growshrink_active_window (struct WinMeta *, char); extern unsigned char meta_keys(int, struct World *, struct WinMeta *, struct Win *, struct Win *, struct Win *, struct Win *); +extern void write_map_objects_monsterdata (void *, FILE *); +extern void readwrite_map_objects_dummy (void *, FILE *); +extern void write_map_objects (void * start, FILE *, void (*) (void *, FILE *) ); +extern void read_map_objects_monsterdata (void *, FILE *); +extern void read_map_objects (void *, FILE *, size_t, void (*) (void *, FILE *) ); +extern void build_map_objects_monsterdata (void *); +extern void build_map_objects_itemdata (void *); +extern void build_map_objects (void *, unsigned char, size_t, void (*) (void *), struct Map *); + #endif -- 2.30.2