home · contact · privacy
Made keybindings array into linked list; on the way rewrote / improved great parts...
[plomrogue] / src / draw_wins.c
1 /* draw_wins.c */
2
3 #include "draw_wins.h"
4 #include <stdlib.h>      /* for free() */
5 #include <stdint.h>      /* for uint16_t */
6 #include <string.h>      /* for strlen() */
7 #include <ncurses.h>     /* for mvwaddch() */
8 #include "windows.h"     /* for structs Win, Frame, for draw_scroll_hint() */
9 #include "misc.h"        /* for center_offset() */
10 #include "keybindings.h" /* for struct KeyBinding, for get_name_to_keycode() */
11 #include "map_objects.h" /* for structs MapObj, Player */
12 #include "map.h"         /* for Map struct */
13 #include "main.h"        /* for World struct */
14 #include "rexit.h"       /* for err_exit() */
15 #include "command_db.h"  /* for get_command_longdesc() */
16 #include "wincontrol.h"  /* for WinConf struct, get_winconf_by_win() */
17
18
19
20 /* Write "text" into window "win" as far as possible. Start on row "start_y". */
21 static void draw_with_linebreaks(struct Win * win, char * text,
22                                  uint16_t start_y);
23
24 /* Write "text" not starting from the top but from the bottom of "win". */
25 static void draw_text_from_bottom(struct Win * win, char * text);
26
27 /* Draw onto "map" in "win" the objects in the chain at "start". */
28 static void draw_map_objects(struct World * world, struct MapObj * start,
29                              struct Map * map, struct Win * win);
30
31
32
33 static void draw_with_linebreaks(struct Win * win, char * text,
34                                  uint16_t start_y)
35 {
36     uint16_t x, y;
37     char toggle;
38     char fin = 0;
39     int16_t z = -1;
40     for (y = start_y; y < win->frame.size.y; y++)
41     {
42         if (0 == fin)
43         {
44             toggle = 0;
45         }
46         for (x = 0; x < win->frame.size.x; x++)
47         {
48             if (0 == toggle)
49             {
50                 z++;
51                 if ('\n' == text[z])
52                 {
53                     toggle = 1;
54                     continue;
55                 }
56                 else
57                 {
58                     mvwaddch(win->frame.curses_win, y, x, text[z]);
59                 }
60                 if ('\n' == text[z+1])
61                 {
62                     z++;
63                     toggle = 1;
64                 }
65                 else if (0 == text[z+1])
66                 {
67                     toggle = 1;
68                     fin = 1;
69                 }
70             }
71         }
72     }
73 }
74
75
76
77 static void draw_text_from_bottom (struct Win * win, char * text)
78 {
79     /* Determine number of lines text would have in a window of win's width,
80      * but infinite height. Treat \n and \0 as control chars for incrementing
81      * y and stopping the loop. Make sure +they* don't count as cell space.
82      */
83     char toggle = 0;
84     uint16_t x, y, offset;
85     int16_t z = -1;
86     for (y = 0; 0 == toggle; y++)
87     {
88         for (x = 0; x < win->frame.size.x; x++)
89         {
90             z++;
91             if ('\n' == text[z])
92             {
93                 break;
94             }
95             if ('\n' == text[z+1])
96             {
97                 z++;
98                 break;
99             }
100             else if (0 == text[z+1])
101             {
102                 toggle = 1;
103                 break;
104             }
105         }
106     }
107     z = -1;
108
109     /* Depending on what's bigger, determine start point in window or text. */
110     uint16_t start_y = 0;
111     if (y < win->frame.size.y)
112     {
113         start_y = win->frame.size.y - y;
114     }
115     else if (y > win->frame.size.y)
116     {
117         offset = y - win->frame.size.y;
118         for (y = 0; y < offset; y++)
119         {
120             for (x = 0; x < win->frame.size.x; x++)
121             {
122                 z++;
123                 if ('\n' == text[z])
124                 {
125                     break;
126                 }
127                 if ('\n' == text[z+1])
128                 {
129                     z++;
130                     break;
131                 }
132             }
133         }
134         text = text + (sizeof(char) * (z + 1));
135     }
136
137     draw_with_linebreaks(win, text, start_y);
138 }
139
140
141
142 static void draw_map_objects(struct World * world, struct MapObj * start,
143                              struct Map * map, struct Win * win)
144 {
145     struct MapObj * o;
146     struct MapObjDef * d;
147     char c;
148     for (o = start; o != 0; o = o->next)
149     {
150         if (   o->pos.y >= map->offset.y
151             && o->pos.y < map->offset.y + win->frame.size.y
152             && o->pos.x >= map->offset.x
153             && o->pos.x < map->offset.x + win->frame.size.x)
154         {
155             d = get_map_obj_def (world, o->type);
156             c = d->mapchar;
157             mvwaddch(win->frame.curses_win,
158                      o->pos.y - map->offset.y, o->pos.x - map->offset.x, c);
159         }
160     }
161 }
162
163
164
165 extern void draw_log_win(struct Win * win)
166 {
167     struct World * world = (struct World *) win->data;
168     draw_text_from_bottom(win, world->log);
169 }
170
171
172
173 extern void draw_map_win(struct Win * win)
174 {
175     struct World * world = (struct World *) win->data;
176     struct Map * map = world->map;
177     struct Player * player = world->player;
178     char * cells = map->cells;
179     uint16_t width_map_av  = map->size.x  - map->offset.x;
180     uint16_t height_map_av = map->size.y - map->offset.y;
181     uint16_t x, y, z;
182     for (y = 0; y < win->frame.size.y; y++)
183     {
184         z = map->offset.x + (map->offset.y + y) * (map->size.x);
185         for (x = 0; x < win->frame.size.x; x++)
186         {
187             if (y < height_map_av && x < width_map_av)
188             {
189                 mvwaddch(win->frame.curses_win, y, x, cells[z]);
190                 z++;
191             }
192         }
193     }
194     draw_map_objects (world, (struct MapObj *) world->item, map, win);
195     draw_map_objects (world, (struct MapObj *) world->monster, map, win);
196     if (   player->pos.y >= map->offset.y
197         && player->pos.y < map->offset.y + win->frame.size.y
198         && player->pos.x >= map->offset.x
199         && player->pos.x < map->offset.x + win->frame.size.x)
200     {
201         mvwaddch(win->frame.curses_win,
202                  player->pos.y - map->offset.y, player->pos.x - map->offset.x,
203                  '@');
204     }
205 }
206
207
208
209 extern void draw_info_win(struct Win * win)
210 {
211     struct World * world = (struct World *) win->data;
212     char * dsc_turn      = "Turn: ";
213     char * dsc_hitpoints = "\nHitpoints: ";
214     char * dsc_score     = "\nScore: ";
215     uint16_t maxl = strlen(dsc_turn) + strlen(dsc_hitpoints) + strlen(dsc_score)
216                     + 10 + 5 + 10;       /* max strlens of numbers to be used */
217     char text[maxl + 1];
218     sprintf(text, "%s%d%s%d%s%d",
219             dsc_turn, world->turn,
220             dsc_hitpoints, world->player->hitpoints,
221             dsc_score, world->score);
222     draw_with_linebreaks(win, text, 0);
223 }
224
225
226
227 extern void draw_keys_win(struct Win * win)
228 {
229     char * err_hint = "Trouble with draw_scroll_hint() in draw_keys_win().";
230     struct World * world = (struct World *) win->data;
231     uint16_t n_keybs = get_n_of_keybs(world);
232     uint16_t offset = center_offset(world->keyswindata->select, n_keybs - 1,
233                                     win->frame.size.y - 1);
234
235     uint8_t keydescwidth = 9 + 1;  /* get_name_to_keycode()'s max length + \0 */
236     char keydesc[keydescwidth];
237
238     uint16_t y, x;
239     for (y = 0; y <= n_keybs - 1 && y < win->frame.size.y; y++)
240     {
241
242         if (0 == y && offset > 0)
243         {
244             exit_err(draw_scroll_hint(&win->frame, y, offset + 1, '^'),
245                      world, err_hint);
246             continue;
247         }
248         else if (win->frame.size.y == y + 1
249                  && 0 < (n_keybs - 1)
250                         - (win->frame.size.y + offset - 1))
251         {
252             exit_err(draw_scroll_hint(&win->frame, y,
253                                       (n_keybs - 1)
254                                       - (offset + win->frame.size.y) + 2,
255                                       'v'),
256                      world, err_hint);
257             continue;
258         }
259
260         attr_t attri = 0;
261         if (y == world->keyswindata->select - offset)
262         {
263             attri = A_REVERSE;
264             if (1 == world->keyswindata->edit)
265             {
266                 attri = attri | A_BLINK;
267             }
268         }
269
270         struct KeyBinding * kb_p = get_keyb_of_n(world, y + offset);
271         char * keyname = get_name_to_keycode(world, kb_p->key);
272         snprintf(keydesc, keydescwidth, "%-9s", keyname);
273         free(keyname);
274         char * cmd_dsc = get_command_longdsc(world, kb_p->name);
275         for (x = 0; x < win->frame.size.x; x++)
276         {
277             if (x < strlen(keydesc))
278             {
279                 mvwaddch(win->frame.curses_win, y, x, keydesc[x] | attri);
280             }
281             else if (   strlen(keydesc) < x
282                      && x < strlen(cmd_dsc) + strlen(keydesc) + 1)
283             {
284                 mvwaddch(win->frame.curses_win, y, x,
285                          cmd_dsc[x - strlen(keydesc) - 1] | attri);
286             }
287             else
288             {
289                 mvwaddch(win->frame.curses_win, y, x, ' ' | attri);
290             }
291         }
292     }
293 }
294
295
296
297 extern void draw_winconf(struct Win * win)
298 {
299     struct World * world = (struct World *) win->data;
300     struct WinConf * wcp = get_winconf_by_win(world, win);
301     char * title = "Window configuration:\n";
302     char * h_d   = "\nWidth to save: ";
303     char * h_pos = " (height in cells)";
304     char * h_neg = " (negative diff: cells to maximum height)";
305     char * w_d   = "\n\nHeight to save: ";
306     char * w_pos = " (width in cells)";
307     char * w_neg = " (negative diff: cells to maximum width)";
308     char * h_t = h_pos;
309     char * w_t = w_pos;
310     if      (1 == wcp->height_type)
311     {
312         h_t = h_neg;
313     }
314     if     (1 == wcp->width_type)
315     {
316         w_t = w_neg;
317     }
318     uint16_t maxl = strlen(title)
319                     + strlen(h_t) + strlen(h_d) + 6
320                     + strlen(w_t) + strlen(w_d) + 6 + 1;
321     char text[maxl + 1];
322     sprintf(text, "%s%s%d%s%s%d%s", title, h_d, wcp->height, h_t,
323                                                 w_d, wcp->width, w_t);
324     draw_with_linebreaks(win, text, 0);
325 }