Mercurial > molko
comparison libmlk-rpg/mlk/rpg/battle-bar-default.c @ 434:4e78f045e8c0
rpg: cleanup hierarchy
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 15 Oct 2022 21:24:17 +0200 |
parents | src/libmlk-rpg/rpg/battle-bar-default.c@862b15c3a3ae |
children | 25a56ca53ac2 |
comparison
equal
deleted
inserted
replaced
433:862b15c3a3ae | 434:4e78f045e8c0 |
---|---|
1 /* | |
2 * battle-bar-default.c -- default battle status bar and menu implementation | |
3 * | |
4 * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
19 #include <assert.h> | |
20 #include <stdio.h> | |
21 #include <stdlib.h> | |
22 #include <string.h> | |
23 | |
24 #include <mlk/core/alloc.h> | |
25 #include <mlk/core/event.h> | |
26 #include <mlk/core/font.h> | |
27 #include <mlk/core/sprite.h> | |
28 #include <mlk/core/trace.h> | |
29 #include <mlk/core/util.h> | |
30 #include <mlk/core/window.h> | |
31 | |
32 #include <mlk/ui/align.h> | |
33 #include <mlk/ui/theme.h> | |
34 | |
35 #include "battle-bar-default.h" | |
36 #include "battle-bar.h" | |
37 #include "battle-state-item.h" | |
38 #include "battle-state-selection.h" | |
39 #include "battle.h" | |
40 #include "character.h" | |
41 #include "inventory.h" | |
42 #include "item.h" | |
43 #include "spell.h" | |
44 | |
45 #define THEME(bar) ((bar)->theme ? (bar)->theme : theme_default()) | |
46 | |
47 struct geo { | |
48 int x, y; | |
49 unsigned int w, h; | |
50 }; | |
51 | |
52 static inline void | |
53 dimensions(struct geo geo[2], const struct battle_bar_default *bar) | |
54 { | |
55 /* 0 == main menu */ | |
56 geo[0].w = bar->w * 0.2; | |
57 geo[0].h = bar->h; | |
58 geo[0].x = bar->x + (bar->w / 2) - (geo[0].w / 2); | |
59 geo[0].y = window.h - bar->h; | |
60 | |
61 /* 1 == status frame */ | |
62 geo[1].x = geo[0].x + geo[0].w; | |
63 geo[1].y = geo[0].y; | |
64 geo[1].w = (bar->w - geo[0].w) / 2; | |
65 geo[1].h = bar->h; | |
66 } | |
67 | |
68 /* | |
69 * The following validate_* functions are called when the user has validated a | |
70 * selection depending on the current menu (e.g. Magic, Items). | |
71 * | |
72 * They change the battle state to the appropriate one. | |
73 */ | |
74 | |
75 static void | |
76 validate_attack(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) | |
77 { | |
78 (void)bar; | |
79 | |
80 struct character *target; | |
81 | |
82 if (sel->index_side == 0) | |
83 target = bt->enemies[sel->index_character]->ch; | |
84 else | |
85 target = bt->team[sel->index_character]->ch; | |
86 | |
87 battle_attack(bt, battle_current(bt)->ch, target); | |
88 } | |
89 | |
90 static void | |
91 validate_magic(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) | |
92 { | |
93 struct character *source = battle_current(bt)->ch; | |
94 const struct spell *spell = source->spells[bar->grid.selected]; | |
95 | |
96 battle_cast(bt, source, spell, sel); | |
97 } | |
98 | |
99 static void | |
100 validate_item(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) | |
101 { | |
102 struct inventory_slot *slot; | |
103 struct battle_entity *source, *target; | |
104 | |
105 if (bar->grid.selected >= INVENTORY_ITEM_MAX) | |
106 return; | |
107 if (!(slot = &bt->inventory->items[bar->grid.selected])) | |
108 return; | |
109 | |
110 source = battle_current(bt); | |
111 target = sel->index_side == 0 | |
112 ? bt->enemies[sel->index_character] | |
113 : bt->team[sel->index_character]; | |
114 | |
115 /* TODO: battle_use? */ | |
116 battle_state_item(bt, source, target, slot); | |
117 } | |
118 | |
119 /* | |
120 * The following functions are used to switch to the battle selection state | |
121 * using the appropriate selector algorithm. For example, an item can only be | |
122 * used on a unique target while a spell can have multiple choices. | |
123 */ | |
124 | |
125 static void | |
126 switch_selection_attack(struct battle_bar_default *bar, struct battle *bt) | |
127 { | |
128 struct selection sel = { | |
129 .allowed_kinds = SELECTION_KIND_ONE, | |
130 .allowed_sides = SELECTION_SIDE_ENEMY, | |
131 .index_side = 0 | |
132 }; | |
133 | |
134 /* Disable handling anymore. */ | |
135 bar->state = BATTLE_BAR_DEFAULT_STATE_NONE; | |
136 | |
137 selection_first(&sel, bt); | |
138 battle_state_selection(bt, &sel); | |
139 } | |
140 | |
141 static void | |
142 switch_selection_spell(struct battle_bar_default *bar, struct battle *bt) | |
143 { | |
144 const struct character *ch = battle_current(bt)->ch; | |
145 const struct spell *sp = ch->spells[bar->grid.selected]; | |
146 struct selection sel = {0}; | |
147 | |
148 if (bar->grid.selected > CHARACTER_SPELL_MAX) | |
149 return; | |
150 if (!(sp = ch->spells[bar->grid.selected]) || sp->mp > (unsigned int)ch->mp) | |
151 return; | |
152 | |
153 /* Use the spell selection algorithm to fill default values. */ | |
154 spell_select(sp, bt, &sel); | |
155 battle_state_selection(bt, &sel); | |
156 | |
157 /* A cursor should be present. */ | |
158 if (!sprite_ok(BATTLE_THEME(bt)->sprites[THEME_SPRITE_CURSOR])) | |
159 tracef("battle: no cursor sprite in theme"); | |
160 } | |
161 | |
162 static void | |
163 switch_selection_item(struct battle *bt) | |
164 { | |
165 const struct selection slt = { | |
166 .allowed_kinds = SELECTION_KIND_ONE, | |
167 .allowed_sides = SELECTION_SIDE_TEAM | SELECTION_SIDE_ENEMY, | |
168 .index_side = 1, | |
169 .index_character = battle_index(bt) | |
170 }; | |
171 | |
172 battle_state_selection(bt, &slt); | |
173 } | |
174 | |
175 /* | |
176 * The following functions actually draw the bar and their components depending | |
177 * on the current selected menu. | |
178 */ | |
179 | |
180 static void | |
181 draw_help(const struct battle_bar_default *bar, const char *what) | |
182 { | |
183 struct label label = {0}; | |
184 unsigned int lw = 0, lh = 0; | |
185 | |
186 label.flags = LABEL_FLAGS_SHADOW; | |
187 label.text = what; | |
188 label_query(&label, &lw, &lh); | |
189 label.x = bar->grid.x + (bar->grid.w / 2) - (lw / 2); | |
190 label.y = bar->grid.y - lh - THEME(bar)->padding; | |
191 label_draw(&label); | |
192 } | |
193 | |
194 static void | |
195 draw_spell_help(const struct battle_bar_default *bar, const struct battle *bt) | |
196 { | |
197 const struct character *ch = battle_current(bt)->ch; | |
198 const struct spell *sp; | |
199 | |
200 if (bar->grid.selected >= CHARACTER_SPELL_MAX) | |
201 return; | |
202 if (!(sp = ch->spells[bar->grid.selected])) | |
203 return; | |
204 | |
205 draw_help(bar, sp->description); | |
206 } | |
207 | |
208 static void | |
209 draw_item_help(const struct battle_bar_default *bar, const struct battle *bt) | |
210 { | |
211 const struct inventory_slot *slot; | |
212 | |
213 if (bar->grid.selected >= INVENTORY_ITEM_MAX) | |
214 return; | |
215 | |
216 slot = &bt->inventory->items[bar->grid.selected]; | |
217 | |
218 if (!slot->item) | |
219 return; | |
220 | |
221 draw_help(bar, slot->item->description); | |
222 } | |
223 | |
224 static void | |
225 draw_status_character_stats(const struct battle_bar_default *bar, | |
226 const struct character *ch, | |
227 int x, | |
228 int y, | |
229 unsigned int h) | |
230 { | |
231 const struct theme *theme = THEME(bar); | |
232 struct label label; | |
233 unsigned int spacing, lw, lh; | |
234 char line[64]; | |
235 | |
236 /* Compute spacing between elements. */ | |
237 spacing = h - (font_height(theme->fonts[THEME_FONT_INTERFACE]) * 3); | |
238 spacing /= 4; | |
239 | |
240 /* Reuse the same label. */ | |
241 label.theme = theme; | |
242 label.text = line; | |
243 label.flags = LABEL_FLAGS_SHADOW; | |
244 | |
245 /* Name. */ | |
246 snprintf(line, sizeof (line), "%s", ch->name); | |
247 label_query(&label, &lw, &lh); | |
248 label.x = x + theme->padding; | |
249 label.y = y + spacing; | |
250 label_draw(&label); | |
251 | |
252 /* HP. */ | |
253 snprintf(line, sizeof (line), "%d/%u", ch->hp, ch->hpmax); | |
254 label_query(&label, &lw, &lh); | |
255 label.x = x + theme->padding; | |
256 label.y = label.y + lh + spacing; | |
257 label_draw(&label); | |
258 | |
259 /* MP. */ | |
260 snprintf(line, sizeof (line), "%d/%u", ch->mp, ch->mpmax); | |
261 label_query(&label, &lw, &lh); | |
262 label.x = x + theme->padding; | |
263 label.y = label.y + lh + spacing; | |
264 label_draw(&label); | |
265 | |
266 /* Status. */ | |
267 /* TODO: list all status. */ | |
268 } | |
269 | |
270 static void | |
271 draw_status_character(const struct battle_bar_default *bar, | |
272 const struct battle *bt, | |
273 const struct character *ch, | |
274 const struct geo *geo, | |
275 unsigned int index) | |
276 { | |
277 int x, y; | |
278 unsigned int w, h; | |
279 | |
280 /* Compute bounding box for rendering. */ | |
281 w = geo->w / bt->teamsz; | |
282 h = geo->h; | |
283 x = geo->x + (index * w); | |
284 y = geo->y; | |
285 | |
286 draw_status_character_stats(bar, ch, x, y, h); | |
287 } | |
288 | |
289 static void | |
290 draw_status_characters(const struct battle_bar_default *bar, | |
291 const struct battle *bt, | |
292 const struct geo *geo) | |
293 { | |
294 const struct battle_entity *et; | |
295 unsigned int index = 0; | |
296 | |
297 BATTLE_TEAM_FOREACH(bt, et) { | |
298 if (character_ok(et->ch)) | |
299 draw_status_character(bar, bt, et->ch, geo, index); | |
300 | |
301 ++index; | |
302 } | |
303 } | |
304 | |
305 static void | |
306 draw_status(const struct battle_bar_default *bar, const struct battle *bt, const struct geo *geo) | |
307 { | |
308 frame_draw(&(const struct frame) { | |
309 .x = geo->x, | |
310 .y = geo->y, | |
311 .w = geo->w, | |
312 .h = geo->h | |
313 }); | |
314 | |
315 draw_status_characters(bar, bt, geo); | |
316 } | |
317 | |
318 static void | |
319 draw_menu(const struct battle_bar_default *bar, const struct geo *geo) | |
320 { | |
321 struct { | |
322 unsigned int w, h; | |
323 enum align align; | |
324 struct label label; | |
325 } buttons[] = { | |
326 { | |
327 .align = ALIGN_TOP, | |
328 .label = { | |
329 .text = "Attack", | |
330 .flags = LABEL_FLAGS_SHADOW | |
331 } | |
332 }, | |
333 { | |
334 .align = ALIGN_RIGHT, | |
335 .label = { | |
336 .text = "Magic", | |
337 .flags = LABEL_FLAGS_SHADOW | |
338 } | |
339 }, | |
340 { | |
341 .align = ALIGN_BOTTOM, | |
342 .label = { | |
343 .text = "Objects", | |
344 .flags = LABEL_FLAGS_SHADOW | |
345 } | |
346 }, | |
347 { | |
348 .align = ALIGN_LEFT, | |
349 .label = { | |
350 .text = "Special", | |
351 .flags = LABEL_FLAGS_SHADOW | |
352 } | |
353 } | |
354 }; | |
355 | |
356 const struct theme *theme = THEME(bar); | |
357 int bx, by; | |
358 unsigned int bw, bh; | |
359 | |
360 /* Compute bounding box with margins removed. */ | |
361 bx = geo->x + theme->padding; | |
362 by = geo->y + theme->padding; | |
363 bw = geo->w - theme->padding * 2; | |
364 bh = geo->h - theme->padding * 2; | |
365 | |
366 /* Draw menu frame. */ | |
367 frame_draw(&(const struct frame) { | |
368 .x = geo->x, | |
369 .y = geo->y, | |
370 .w = geo->w, | |
371 .h = geo->h | |
372 }); | |
373 | |
374 for (size_t i = 0; i < UTIL_SIZE(buttons); ++i) { | |
375 buttons[i].label.theme = theme; | |
376 | |
377 label_query(&buttons[i].label, &buttons[i].w, &buttons[i].h); | |
378 | |
379 /* Change theme if it's selected. */ | |
380 if ((size_t)bar->menu == i) | |
381 buttons[i].label.flags |= LABEL_FLAGS_SELECTED; | |
382 else | |
383 buttons[i].label.flags &= ~LABEL_FLAGS_SELECTED; | |
384 | |
385 align(buttons[i].align, | |
386 &buttons[i].label.x, &buttons[i].label.y, buttons[i].w, buttons[i].h, | |
387 bx, by, bw, bh); | |
388 label_draw(&buttons[i].label); | |
389 } | |
390 } | |
391 | |
392 /* | |
393 * This function is called only in the first level of the bar menu: selecting | |
394 * one of the Attack, Magic, Item and Special items. | |
395 */ | |
396 static void | |
397 handle_keydown_menu(struct battle_bar_default *bar, struct battle *bt, const union event *ev) | |
398 { | |
399 (void)bt; | |
400 | |
401 switch (ev->key.key) { | |
402 case KEY_UP: | |
403 bar->menu = BATTLE_BAR_DEFAULT_MENU_ATTACK; | |
404 break; | |
405 case KEY_RIGHT: | |
406 bar->menu = BATTLE_BAR_DEFAULT_MENU_MAGIC; | |
407 break; | |
408 case KEY_DOWN: | |
409 bar->menu = BATTLE_BAR_DEFAULT_MENU_ITEM; | |
410 break; | |
411 case KEY_LEFT: | |
412 bar->menu = BATTLE_BAR_DEFAULT_MENU_SPECIAL; | |
413 break; | |
414 case KEY_ENTER: | |
415 /* | |
416 * At this step, attack does not require opening the sub menu so | |
417 * we change selection state immediately if needed. | |
418 */ | |
419 switch (bar->menu) { | |
420 case BATTLE_BAR_DEFAULT_MENU_ATTACK: | |
421 switch_selection_attack(bar, bt); | |
422 break; | |
423 case BATTLE_BAR_DEFAULT_MENU_ITEM: | |
424 battle_bar_default_open_item(bar, bt); | |
425 break; | |
426 case BATTLE_BAR_DEFAULT_MENU_MAGIC: | |
427 battle_bar_default_open_magic(bar, bt, battle_current(bt)->ch); | |
428 break; | |
429 default: | |
430 break; | |
431 } | |
432 break; | |
433 default: | |
434 break; | |
435 } | |
436 } | |
437 | |
438 /* | |
439 * This function is called when we're selecting a submenu entry from Items | |
440 * and Magic. | |
441 */ | |
442 static void | |
443 handle_keydown_grid(struct battle_bar_default *bar, struct battle *bt, const union event *ev) | |
444 { | |
445 /* Go back to main menu if I press escape. */ | |
446 if (ev->key.key == KEY_ESCAPE) | |
447 bar->state = BATTLE_BAR_DEFAULT_STATE_MENU; | |
448 else if (gridmenu_handle(&bar->grid, ev)) { | |
449 switch (bar->menu) { | |
450 case BATTLE_BAR_DEFAULT_MENU_MAGIC: | |
451 switch_selection_spell(bar, bt); | |
452 break; | |
453 case BATTLE_BAR_DEFAULT_MENU_ITEM: | |
454 switch_selection_item(bt); | |
455 break; | |
456 default: | |
457 break; | |
458 } | |
459 } | |
460 } | |
461 | |
462 static void | |
463 handle_keydown(struct battle_bar_default *bar, struct battle *bt, const union event *ev) | |
464 { | |
465 assert(ev->type == EVENT_KEYDOWN); | |
466 | |
467 static void (*handlers[])(struct battle_bar_default *, struct battle *, const union event *) = { | |
468 [BATTLE_BAR_DEFAULT_STATE_MENU] = handle_keydown_menu, | |
469 [BATTLE_BAR_DEFAULT_STATE_GRID] = handle_keydown_grid | |
470 }; | |
471 | |
472 if (handlers[bar->state]) | |
473 handlers[bar->state](bar, bt, ev); | |
474 } | |
475 | |
476 #if 0 | |
477 | |
478 static void | |
479 handle_clickdown(struct battle_bar_default *bar, struct battle *bt, const union event *ev) | |
480 { | |
481 assert(ev->type == EVENT_CLICKDOWN); | |
482 | |
483 (void)bar; | |
484 (void)bt; | |
485 | |
486 switch (bar->state) { | |
487 case BATTLE_BAR_DEFAULT_STATE_MENU: | |
488 /* We are selecting a main menu entry. */ | |
489 /* TODO: implement click here too. */ | |
490 break; | |
491 case BATTLE_BAR_DEFAULT_STATE_SUB: | |
492 /* We are in the sub menu (objects/spells). */ | |
493 if (bar->sub_grid.state == GRIDMENU_STATE_ACTIVATED) | |
494 default: | |
495 break; | |
496 } | |
497 | |
498 return 0; | |
499 } | |
500 | |
501 #endif | |
502 | |
503 static void | |
504 self_start(struct battle_bar *bar, struct battle *bt) | |
505 { | |
506 (void)bt; | |
507 | |
508 battle_bar_default_start(bar->data); | |
509 } | |
510 | |
511 static void | |
512 self_select(struct battle_bar *bar, struct battle *bt, const struct selection *sel) | |
513 { | |
514 battle_bar_default_select(bar->data, bt, sel); | |
515 } | |
516 | |
517 static void | |
518 self_handle(struct battle_bar *bar, struct battle *bt, const union event *ev) | |
519 { | |
520 battle_bar_default_handle(bar->data, bt, ev); | |
521 } | |
522 | |
523 static void | |
524 self_draw(const struct battle_bar *bar, const struct battle *bt) | |
525 { | |
526 battle_bar_default_draw(bar->data, bt); | |
527 } | |
528 | |
529 void | |
530 battle_bar_default_init(struct battle_bar_default *bar) | |
531 { | |
532 assert(bar); | |
533 | |
534 struct geo geo[2]; | |
535 | |
536 memset(bar, 0, sizeof (*bar)); | |
537 | |
538 bar->w = window.w; | |
539 bar->h = window.h * 0.12; | |
540 bar->x = 0; | |
541 bar->y = window.h - bar->h; | |
542 | |
543 dimensions(geo, bar); | |
544 | |
545 gridmenu_init(&bar->grid, 2, 2, NULL, 0); | |
546 gridmenu_resize(&bar->grid, bar->x, geo[0].y, geo[1].w, bar->h); | |
547 bar->grid.theme = bar->theme; | |
548 } | |
549 | |
550 void | |
551 battle_bar_default_open_magic(struct battle_bar_default *bar, const struct battle *bt, struct character *ch) | |
552 { | |
553 assert(bar); | |
554 assert(bt); | |
555 assert(ch); | |
556 | |
557 (void)bt; | |
558 | |
559 bar->items = alloc_rearray0(bar->items, bar->itemsz, | |
560 CHARACTER_SPELL_MAX, sizeof (*bar->items)); | |
561 bar->itemsz = CHARACTER_SPELL_MAX; | |
562 bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; | |
563 | |
564 for (size_t i = 0; i < CHARACTER_SPELL_MAX; ++i) | |
565 if (ch->spells[i]) | |
566 bar->items[i] = ch->spells[i]->name; | |
567 | |
568 bar->grid.items = bar->items; | |
569 bar->grid.itemsz = bar->itemsz; | |
570 } | |
571 | |
572 void | |
573 battle_bar_default_open_item(struct battle_bar_default *bar, const struct battle *bt) | |
574 { | |
575 assert(bar); | |
576 assert(bt); | |
577 | |
578 /* TODO: not implemented yet. */ | |
579 (void)bar; | |
580 (void)bt; | |
581 #if 0 | |
582 for (size_t i = 0; i < INVENTORY_ITEM_MAX; ++i) { | |
583 if (bt->inventory->items[i].item) { | |
584 snprintf(bar->sub_items[i], sizeof (bar->sub_items[i]), "%-16s %u", | |
585 bt->inventory->items[i].item->name, bt->inventory->items[i].amount); | |
586 bar->sub_grid.menu[i] = bar->sub_items[i]; | |
587 } | |
588 } | |
589 | |
590 bar->state = BATTLE_BAR_DEFAULT_STATE_GRID; | |
591 #endif | |
592 } | |
593 | |
594 void | |
595 battle_bar_default_start(struct battle_bar_default *bar) | |
596 { | |
597 assert(bar); | |
598 | |
599 bar->menu = BATTLE_BAR_DEFAULT_MENU_ATTACK; | |
600 bar->state = BATTLE_BAR_DEFAULT_STATE_MENU; | |
601 } | |
602 | |
603 /* | |
604 * Apply the battle selection for the current menu item. This function is called | |
605 * from the battle-state-selection state when the user validated the selection. | |
606 */ | |
607 void | |
608 battle_bar_default_select(struct battle_bar_default *bar, struct battle *bt, const struct selection *sel) | |
609 { | |
610 assert(bar); | |
611 assert(bt); | |
612 assert(sel); | |
613 | |
614 static void (*validate[])(struct battle_bar_default *, struct battle *, const struct selection *) = { | |
615 [BATTLE_BAR_DEFAULT_MENU_ATTACK] = validate_attack, | |
616 [BATTLE_BAR_DEFAULT_MENU_ITEM] = validate_item, | |
617 [BATTLE_BAR_DEFAULT_MENU_MAGIC] = validate_magic, | |
618 [BATTLE_BAR_DEFAULT_MENU_SPECIAL] = NULL | |
619 }; | |
620 | |
621 if (validate[bar->menu]) | |
622 validate[bar->menu](bar, bt, sel); | |
623 } | |
624 | |
625 void | |
626 battle_bar_default_handle(struct battle_bar_default *bar, struct battle *bt, const union event *ev) | |
627 { | |
628 assert(bar); | |
629 assert(bt); | |
630 assert(ev); | |
631 | |
632 static void (*handlers[])(struct battle_bar_default *, struct battle *, const union event *) = { | |
633 [EVENT_KEYDOWN] = handle_keydown, | |
634 [EVENT_NUM] = NULL | |
635 }; | |
636 | |
637 if (handlers[ev->type]) | |
638 handlers[ev->type](bar, bt, ev); | |
639 } | |
640 | |
641 void | |
642 battle_bar_default_draw(const struct battle_bar_default *bar, const struct battle *bt) | |
643 { | |
644 assert(bar); | |
645 assert(bt); | |
646 | |
647 struct geo geo[2]; | |
648 | |
649 dimensions(geo, bar); | |
650 draw_menu(bar, &geo[0]); | |
651 draw_status(bar, bt, &geo[1]); | |
652 | |
653 if (bar->state == BATTLE_BAR_DEFAULT_STATE_GRID) { | |
654 switch (bar->menu) { | |
655 case BATTLE_BAR_DEFAULT_MENU_MAGIC: | |
656 draw_spell_help(bar, bt); | |
657 break; | |
658 case BATTLE_BAR_DEFAULT_MENU_ITEM: | |
659 draw_item_help(bar, bt); | |
660 break; | |
661 default: | |
662 break; | |
663 } | |
664 } | |
665 | |
666 /* Sub menu is only shown if state is set to it. */ | |
667 if (bar->state == BATTLE_BAR_DEFAULT_STATE_GRID) | |
668 gridmenu_draw(&bar->grid); | |
669 } | |
670 | |
671 void | |
672 battle_bar_default_finish(struct battle_bar_default *bar) | |
673 { | |
674 assert(bar); | |
675 | |
676 free(bar->items); | |
677 memset(bar, 0, sizeof (*bar)); | |
678 } | |
679 | |
680 void | |
681 battle_bar_default(struct battle_bar_default *self, struct battle_bar *bar) | |
682 { | |
683 assert(self); | |
684 assert(bar); | |
685 | |
686 memset(bar, 0, sizeof (*bar)); | |
687 | |
688 bar->data = self; | |
689 bar->start = self_start; | |
690 bar->select = self_select; | |
691 bar->handle = self_handle; | |
692 bar->draw = self_draw; | |
693 } |