31 struct Player * player;
32 struct KeyBinding * keybindings;
33 struct KeysWinData * keyswindata; };
35 void draw_with_linebreaks (struct Win * win, char * text, int start_y) {
36 // Write text into window content space. Start on row start_y. Fill unused rows with whitespace.
41 for (y = start_y; y < win->height; y++) {
44 for (x = 0; x < win->width; x++) {
47 if ('\n' == text[z]) {
51 mvwaddch(win->curses, y, x, text[z]);
52 if ('\n' == text[z+1]) {
55 else if (0 == text[z+1]) {
59 void draw_text_from_bottom (struct Win * win, char * text) {
60 // Draw text from end/bottom to the top.
64 for (y = 0; 0 == toggle; y++) // Determine number of lines text would have in
65 for (x = 0; x < win->width; x++) { // a window of available width, but infinite height.
67 if ('\n' == text[z]) // Treat \n and \0 as control characters for incrementing y and stopping
68 break; // the loop. Make sure they don't count as cell space themselves.
69 if ('\n' == text[z+1]) {
72 else if (0 == text[z+1]) {
77 if (y < win->height) // Depending on what is bigger, determine start point in window or in text.
78 start_y = win->height - y;
79 else if (y > win->height) {
80 offset = y - win->height;
81 for (y = 0; y < offset; y++)
82 for (x = 0; x < win->width; x++) {
86 if ('\n' == text[z+1]) {
89 text = text + (sizeof(char) * (z + 1)); }
90 draw_with_linebreaks(win, text, start_y); }
92 void draw_log (struct Win * win) {
93 // Draw log text from world struct in win->data from bottom to top.
94 struct World world = * (struct World *) win->data;
95 draw_text_from_bottom(win, world.log); }
97 void draw_map (struct Win * win) {
98 // Draw map determined by win->data Map struct into window. Respect offset.
99 struct World * world = (struct World *) win->data;
100 struct Map * map = world->map;
101 struct Player * player = world->player;
102 char * cells = map->cells;
103 int width_map_av = map->width - map->offset_x;
104 int height_map_av = map->height - map->offset_y;
106 for (y = 0; y < win->height; y++) {
107 z = map->offset_x + (map->offset_y + y) * (map->width);
108 for (x = 0; x < win->width; x++) {
109 if (y < height_map_av && x < width_map_av) {
110 if (z == (map->width * player->y) + player->x)
111 mvwaddch(win->curses, y, x, '@');
113 mvwaddch(win->curses, y, x, cells[z]);
116 void draw_info (struct Win * win) {
117 // Draw info window by appending win->data integer value to "Turn: " display.
118 struct World world = * (struct World *) win->data;
119 int count = world.turn;
121 snprintf(text, 100, "Turn: %d", count);
122 draw_with_linebreaks(win, text, 0); }
124 void toggle_window (struct WinMeta * win_meta, struct Win * win) {
125 // Toggle display of window win.
126 if (0 != win->curses)
127 suspend_window(win_meta, win);
129 append_window(win_meta, win); }
131 struct Map init_map () {
132 // Initialize map with some experimental start values.
138 map.cells = malloc(map.width * map.height);
140 for (y = 0; y < map.height; y++)
141 for (x = 0; x < map.width; x++)
142 map.cells[(y * map.width) + x] = '.';
143 map.cells[(5 * map.width) + 5] = 'X';
144 map.cells[(3 * map.width) + 8] = 'X';
145 map.cells[(8 * map.width) + 3] = 'X';
148 void update_info (struct World * world) {
149 // Update info data by incrementing turn value.
152 void update_log (struct World * world, char * text) {
153 // Update log with new text to be appended.
155 int len_old = strlen(world->log);
156 int len_new = strlen(text);
157 int len_whole = len_old + len_new + 1;
158 new_text = calloc(len_whole, sizeof(char));
159 memcpy(new_text, world->log, len_old);
160 memcpy(new_text + len_old, text, len_new);
162 world->log = new_text; }
164 int get_action_key (struct KeyBinding * keybindings, char * name) {
165 // Return key matching name in keybindings.
167 while (strcmp(keybindings[i].name, name) )
169 return keybindings[i].key; }
171 char * get_keyname(int keycode) {
172 // Translate some keycodes to readable names of max 9 chars.
174 keyname = malloc(15);
175 if (32 < keycode && keycode < 127)
176 sprintf(keyname, "%c", keycode);
177 else if (keycode == 9)
178 sprintf(keyname, "TAB");
179 else if (keycode == 10)
180 sprintf(keyname, "RETURN");
181 else if (keycode == 27)
182 sprintf(keyname, "ESCAPE");
183 else if (keycode == 32)
184 sprintf(keyname, "SPACE");
185 else if (keycode == KEY_UP)
186 sprintf(keyname, "UP");
187 else if (keycode == KEY_DOWN)
188 sprintf(keyname, "DOWN");
189 else if (keycode == KEY_LEFT)
190 sprintf(keyname, "LEFT");
191 else if (keycode == KEY_RIGHT)
192 sprintf(keyname, "RIGHT");
193 else if (keycode == KEY_HOME)
194 sprintf(keyname, "HOME");
195 else if (keycode == KEY_BACKSPACE)
196 sprintf(keyname, "BACKSPACE");
197 else if (keycode >= KEY_F0 && keycode <= KEY_F(63)) {
198 int f = keycode - KEY_F0;
199 sprintf(keyname, "F%d", f); }
200 else if (keycode == KEY_DC)
201 sprintf(keyname, "DELETE");
202 else if (keycode == KEY_IC)
203 sprintf(keyname, "INSERT");
204 else if (keycode == KEY_NPAGE)
205 sprintf(keyname, "NEXT PAGE");
206 else if (keycode == KEY_PPAGE)
207 sprintf(keyname, "PREV PAGE");
208 else if (keycode == KEY_END)
209 sprintf(keyname, "END");
211 sprintf(keyname, "(unknown)");
214 void draw_keys_window (struct Win * win) {
215 // Draw keybinding window.
216 struct World * world = (struct World *) win->data;
217 struct KeysWinData * keyswindata = (struct KeysWinData *) world->keyswindata;
218 struct KeyBinding * keybindings = world->keybindings;
220 if (keyswindata->max >= win->height) {
221 if (keyswindata->select > win->height / 2) {
222 if (keyswindata->select < (keyswindata->max - (win->height / 2)))
223 offset = keyswindata->select - (win->height / 2);
225 offset = keyswindata->max - win->height + 1; } }
226 int keydescwidth = 9 + 1; // max length assured by get_keyname() + \0
227 char * keydesc = malloc(keydescwidth);
231 for (y = 0; y <= keyswindata->max && y < win->height; y++) {
233 if (y == keyswindata->select - offset) {
235 if (1 == keyswindata->edit)
236 attri = attri | A_BLINK; }
237 keyname = get_keyname(keybindings[y + offset].key);
238 snprintf(keydesc, keydescwidth, "%-9s", keyname);
240 for (x = 0; x < win->width; x++)
241 if (x < strlen(keydesc))
242 mvwaddch(win->curses, y, x, keydesc[x] | attri);
243 else if (strlen(keydesc) < x && x < strlen(keybindings[y + offset].name) + strlen(keydesc) + 1)
244 mvwaddch(win->curses, y, x, keybindings[y + offset].name[x - strlen(keydesc) - 1] | attri);
246 mvwaddch(win->curses, y, x, ' ' | attri); }
249 void init_keybindings(struct World * world) {
250 // Initialize keybindings from file "keybindings".
251 FILE * file = fopen("keybindings", "r");
260 if (c_count > linemax)
261 linemax = c_count + 1;
264 struct KeyBinding * keybindings = malloc(lines * sizeof(struct KeyBinding));
265 fseek(file, 0, SEEK_SET);
266 char * command = malloc(linemax);
269 while (fgets(command, linemax, file)) {
270 keybindings[commcount].key = atoi(command);
271 cmdptr = strchr(command, ' ') + 1;
272 keybindings[commcount].name = malloc(strlen(cmdptr));
273 memcpy(keybindings[commcount].name, cmdptr, strlen(cmdptr) - 1);
274 keybindings[commcount].name[strlen(cmdptr) - 1] = '\0';
278 struct KeysWinData * keyswindata = malloc(sizeof(struct KeysWinData));
279 keyswindata->max = lines - 1;
280 keyswindata->select = 0;
281 keyswindata->edit = 0;
282 world->keybindings = keybindings;
283 world->keyswindata = keyswindata; }
285 void save_keybindings(struct World * world) {
286 // Write keybindings to keybindings file.
287 struct KeysWinData * keyswindata = (struct KeysWinData *) world->keyswindata;
288 struct KeyBinding * keybindings = world->keybindings;
289 FILE * file = fopen("keybindings", "w");
292 for (i = 0; i <= keyswindata->max; i++)
293 if (strlen(keybindings[i].name) > linemax)
294 linemax = strlen(keybindings[i].name);
295 linemax = linemax + 6; // + 6 = + 3 digits + whitespace + newline + null byte
296 char * line = malloc(linemax);
297 for (i = 0; i <= keyswindata->max; i++) {
298 snprintf(line, linemax, "%d %s\n", keybindings[i].key, keybindings[i].name);
299 fwrite(line, sizeof(char), strlen(line), file); }
305 init_keybindings(&world);
306 struct Map map = init_map();
308 struct Player player;
311 world.player = &player;
313 WINDOW * screen = initscr();
316 keypad(screen, TRUE);
318 struct WinMeta win_meta = init_win_meta(screen);
320 struct Win win_keys = init_window(&win_meta, "Keys");
321 win_keys.draw = draw_keys_window;
322 win_keys.data = &world;
324 struct Win win_map = init_window(&win_meta, "Map");
325 win_map.draw = draw_map;
326 win_map.data = &world;
329 struct Win win_info = init_window(&win_meta, "Info");
330 win_info.draw = draw_info;
331 win_info.data = &world;
333 world.log = calloc(1, sizeof(char));
334 struct Win win_log = init_window(&win_meta, "Log");
335 win_log.draw = draw_log;
336 win_log.data = &world;
337 update_log (&world, "Start!");
341 draw_all_windows (&win_meta);
343 if (key == get_action_key(world.keybindings, "quit"))
345 else if (key == get_action_key(world.keybindings, "scroll pad right"))
346 win_meta.pad_offset++;
347 else if (key == get_action_key(world.keybindings, "scroll pad left") && win_meta.pad_offset > 0)
348 win_meta.pad_offset--;
349 else if (key == get_action_key(world.keybindings, "toggle keys window"))
350 toggle_window(&win_meta, &win_keys);
351 else if (key == get_action_key(world.keybindings, "toggle map window"))
352 toggle_window(&win_meta, &win_map);
353 else if (key == get_action_key(world.keybindings, "toggle info window"))
354 toggle_window(&win_meta, &win_info);
355 else if (key == get_action_key(world.keybindings, "toggle log window"))
356 toggle_window(&win_meta, &win_log);
357 else if (key == get_action_key(world.keybindings, "cycle forwards") && win_meta.active != 0)
358 cycle_active_window(&win_meta, 'n');
359 else if (key == get_action_key(world.keybindings, "cycle backwards") && win_meta.active != 0)
360 cycle_active_window(&win_meta, 'p');
361 else if (key == get_action_key(world.keybindings, "shift forwards") && win_meta.active != 0)
362 shift_window(&win_meta, 'f');
363 else if (key == get_action_key(world.keybindings, "shift backwards") && win_meta.active != 0)
364 shift_window(&win_meta, 'b');
365 else if (key == get_action_key(world.keybindings, "grow horizontally") && win_meta.active != 0)
366 resize_window(&win_meta, '*');
367 else if (key == get_action_key(world.keybindings, "shrink horizontally") && win_meta.active != 0)
368 resize_window(&win_meta, '_');
369 else if (key == get_action_key(world.keybindings, "grow vertically") && win_meta.active != 0)
370 resize_window(&win_meta, '+');
371 else if (key == get_action_key(world.keybindings, "shrink vertically") && win_meta.active != 0)
372 resize_window(&win_meta, '-');
373 else if (key == get_action_key(world.keybindings, "save keys"))
374 save_keybindings(&world);
375 else if (key == get_action_key(world.keybindings, "keys nav up") && world.keyswindata->select > 0)
376 world.keyswindata->select--;
377 else if (key == get_action_key(world.keybindings, "keys nav down") && world.keyswindata->select < world.keyswindata->max)
378 world.keyswindata->select++;
379 else if (key == get_action_key(world.keybindings, "keys mod")) {
380 world.keyswindata->edit = 1;
381 draw_all_windows (&win_meta);
383 if (key < 1000) // ensure maximum of three digits in key code field
384 world.keybindings[world.keyswindata->select].key = key;
385 world.keyswindata->edit = 0; }
386 else if (key == get_action_key(world.keybindings, "map up") && map.offset_y > 0)
388 else if (key == get_action_key(world.keybindings, "map down"))
390 else if (key == get_action_key(world.keybindings, "map right"))
392 else if (key == get_action_key(world.keybindings, "map left") && map.offset_x > 0)
394 else if (key == get_action_key(world.keybindings, "player down") && player.y < map.height - 1) {
395 update_info (&world);
396 update_log (&world, "\nYou move south.");
398 else if (key == get_action_key(world.keybindings, "player up") && player.y > 0) {
399 update_info (&world);
400 update_log (&world, "\nYou move north.");
402 else if (key == get_action_key(world.keybindings, "player right") && player.x < map.width - 1) {
403 update_info (&world);
404 update_log (&world, "\nYou move east.");
406 else if (key == get_action_key(world.keybindings, "player left") && player.x > 0) {
407 update_info (&world);
408 update_log (&world, "\nYou move west.");
410 else if (key == get_action_key(world.keybindings, "wait") ) {
411 update_info (&world);
412 update_log (&world, "\nYou wait."); } }
415 for (key = 0; key <= world.keyswindata->max; key++)
416 free(world.keybindings[key].name);
417 free(world.keybindings);
418 free(world.keyswindata);