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