]> git.lizzy.rs Git - nothing.git/blob - src/game/level_picker.c
(#824) Introduce UndoHistory
[nothing.git] / src / game / level_picker.c
1 #include <stdio.h>
2
3 #include "./level_picker.h"
4 #include "game/level/background.h"
5 #include "game/sprite_font.h"
6 #include "system/lt.h"
7 #include "system/nth_alloc.h"
8 #include "system/stacktrace.h"
9 #include "system/str.h"
10 #include "ui/list_selector.h"
11 #include "system/log.h"
12 #include "game/level_folder.h"
13 #include "ui/wiggly_text.h"
14
15 #define TITLE_MARGIN_TOP 100.0f
16 #define TITLE_MARGIN_BOTTOM 100.0f
17
18 struct LevelPicker
19 {
20     Lt *lt;
21     Background *background;
22     Vec camera_position;
23     LevelFolder *level_folder;
24     WigglyText wiggly_text;
25     ListSelector *list_selector;
26 };
27
28 LevelPicker *create_level_picker(const Sprite_font *sprite_font, const char *dirpath)
29 {
30     trace_assert(dirpath);
31
32     Lt *lt = create_lt();
33
34     LevelPicker *level_picker = PUSH_LT(
35         lt,
36         nth_calloc(1, sizeof(LevelPicker)),
37         free);
38     if (level_picker == NULL) {
39         RETURN_LT(lt, NULL);
40     }
41     level_picker->lt = lt;
42
43     level_picker->background = PUSH_LT(
44         lt,
45         create_background(hexstr("073642")),
46         destroy_background);
47     if (level_picker->background == NULL) {
48         RETURN_LT(lt, NULL);
49     }
50
51     level_picker->camera_position = vec(0.0f, 0.0f);
52
53     level_picker->level_folder = PUSH_LT(
54         lt,
55         create_level_folder(dirpath),
56         destroy_level_folder);
57     if (level_picker->level_folder == NULL) {
58         RETURN_LT(lt, NULL);
59     }
60
61     level_picker->wiggly_text = (WigglyText) {
62         .text = "Select Level",
63         .scale = {10.0f, 10.0f},
64         .color = COLOR_WHITE,
65     };
66
67     level_picker->list_selector = PUSH_LT(
68         lt,
69         create_list_selector(
70             sprite_font,
71             level_folder_titles(level_picker->level_folder),
72             level_folder_count(level_picker->level_folder),
73             vec(5.0f, 5.0f),
74             50.0f),
75         destroy_list_selector);
76     if (level_picker->list_selector == NULL) {
77         RETURN_LT(lt, NULL);
78     }
79
80     return level_picker;
81 }
82
83 void destroy_level_picker(LevelPicker *level_picker)
84 {
85     trace_assert(level_picker);
86     RETURN_LT0(level_picker->lt);
87 }
88
89 int level_picker_render(const LevelPicker *level_picker,
90                         Camera *camera,
91                         SDL_Renderer *renderer)
92 {
93     trace_assert(level_picker);
94     trace_assert(renderer);
95
96     const Rect viewport = camera_view_port_screen(camera);
97
98     if (background_render(level_picker->background, camera) < 0) {
99         return -1;
100     }
101
102     const Vec title_size = wiggly_text_size(&level_picker->wiggly_text, camera);
103
104     if (wiggly_text_render(
105             &level_picker->wiggly_text,
106             camera,
107             vec(viewport.w * 0.5f - title_size.x * 0.5f, TITLE_MARGIN_TOP)) < 0) {
108         return -1;
109     }
110
111     if (list_selector_render(level_picker->list_selector, renderer) < 0) {
112         return -1;
113     }
114
115     {
116         /* CSS */
117         const float padding = 20.0f;
118         const Point size = vec(3.0f, 3.0f);
119         const Point position = vec(0.0f, viewport.h - size.y * FONT_CHAR_HEIGHT);
120
121         /* HTML */
122         if (camera_render_text_screen(
123                 camera,
124                 "Press 'N' to create new level",
125                 size,
126                 COLOR_WHITE,
127                 vec(position.x + padding,
128                     position.y - padding)) < 0) {
129             return -1;
130         }
131     }
132
133     return 0;
134 }
135
136 int level_picker_update(LevelPicker *level_picker,
137                         float delta_time)
138 {
139     trace_assert(level_picker);
140
141     vec_add(&level_picker->camera_position,
142             vec(50.0f * delta_time, 0.0f));
143
144     if (wiggly_text_update(&level_picker->wiggly_text, delta_time) < 0) {
145         return -1;
146     }
147
148     return 0;
149 }
150
151 int level_picker_event(LevelPicker *level_picker,
152                        const SDL_Event *event,
153                        const Camera *camera)
154 {
155     trace_assert(level_picker);
156     trace_assert(event);
157
158     switch (event->type) {
159     case SDL_WINDOWEVENT: {
160         switch (event->window.event) {
161         case SDL_WINDOWEVENT_SHOWN:
162         case SDL_WINDOWEVENT_RESIZED: {
163             const Vec font_scale = vec(5.0f, 5.0f);
164             const float padding_bottom = 50.0f;
165
166             int width;
167             SDL_GetWindowSize(SDL_GetWindowFromID(event->window.windowID), &width, NULL);
168
169             const Vec title_size = wiggly_text_size(&level_picker->wiggly_text, camera);
170
171             const Vec selector_size = list_selector_size(
172                 level_picker->list_selector,
173                 font_scale,
174                 padding_bottom);
175
176             list_selector_move(
177                 level_picker->list_selector,
178                 vec((float)width * 0.5f - selector_size.x * 0.5f,
179                     TITLE_MARGIN_TOP + title_size.y + TITLE_MARGIN_BOTTOM));
180         } break;
181         }
182     } break;
183     }
184
185     return list_selector_event(level_picker->list_selector, event);
186 }
187
188 int level_picker_input(LevelPicker *level_picker,
189                        const Uint8 *const keyboard_state,
190                        SDL_Joystick *the_stick_of_joy)
191 {
192     trace_assert(level_picker);
193     trace_assert(keyboard_state);
194     (void) the_stick_of_joy;
195     return 0;
196 }
197
198 const char *level_picker_selected_level(const LevelPicker *level_picker)
199 {
200     trace_assert(level_picker);
201
202     const int selected_index = list_selector_selected(level_picker->list_selector);
203     if (selected_index < 0) {
204         return NULL;
205     }
206
207     const char **filenames = level_folder_filenames(level_picker->level_folder);
208
209     return filenames[selected_index];
210 }
211
212 void level_picker_clean_selection(LevelPicker *level_picker)
213 {
214     trace_assert(level_picker);
215     list_selector_clean_selection(level_picker->list_selector);
216 }
217
218 int level_picker_enter_camera_event(LevelPicker *level_picker,
219                                     Camera *camera)
220 {
221     camera_center_at(camera, level_picker->camera_position);
222     return 0;
223 }