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