#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;
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;
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;
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;
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;
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; }
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) {
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) {
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;
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;
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.
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();