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