]> git.lizzy.rs Git - nothing.git/blob - src/game/level/platforms.c
(#639) Make rigid bodies interact with platforms
[nothing.git] / src / game / level / platforms.c
1 #include <SDL2/SDL.h>
2 #include "system/stacktrace.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7
8 #include "platforms.h"
9 #include "system/lt.h"
10 #include "system/lt/lt_adapters.h"
11 #include "system/line_stream.h"
12 #include "system/nth_alloc.h"
13 #include "system/log.h"
14
15 struct Platforms {
16     Lt *lt;
17
18     Rect *rects;
19     Color *colors;
20     size_t rects_size;
21 };
22
23 Platforms *create_platforms_from_line_stream(LineStream *line_stream)
24 {
25     trace_assert(line_stream);
26
27     Lt *const lt = create_lt();
28     if (lt == NULL) {
29         return NULL;
30     }
31
32     Platforms *platforms = PUSH_LT(lt, nth_alloc(sizeof(Platforms)), free);
33     if (platforms == NULL) {
34         RETURN_LT(lt, NULL);
35     }
36
37     platforms->rects_size = 0;
38     if (sscanf(
39             line_stream_next(line_stream),
40             "%lu",
41             &platforms->rects_size) == EOF) {
42         log_fail("Could not read amount of platforms\n");
43         RETURN_LT(lt, NULL);
44     }
45
46     platforms->rects = PUSH_LT(lt, nth_alloc(sizeof(Rect) * platforms->rects_size), free);
47     if (platforms->rects == NULL) {
48         RETURN_LT(lt, NULL);
49     }
50
51     platforms->colors = PUSH_LT(lt, nth_alloc(sizeof(Color) * platforms->rects_size), free);
52     if (platforms->colors == NULL) {
53         RETURN_LT(lt, NULL);
54     }
55
56     char color[7];
57     for (size_t i = 0; i < platforms->rects_size; ++i) {
58         if (sscanf(line_stream_next(line_stream),
59                    "%f%f%f%f%6s\n",
60                    &platforms->rects[i].x, &platforms->rects[i].y,
61                    &platforms->rects[i].w, &platforms->rects[i].h,
62                    color) < 0) {
63             log_fail("Could not read %dth platform\n", i);
64             RETURN_LT(lt, NULL);
65         }
66         platforms->colors[i] = hexstr(color);
67     }
68
69     platforms->lt = lt;
70
71     return platforms;
72 }
73
74 void destroy_platforms(Platforms *platforms)
75 {
76     trace_assert(platforms);
77     RETURN_LT0(platforms->lt);
78 }
79
80 int platforms_save_to_file(const Platforms *platforms,
81                            const char *filename)
82 {
83     trace_assert(platforms);
84     trace_assert(filename);
85
86     Lt *const lt = create_lt();
87     if (lt == NULL) {
88         return -1;
89     }
90
91     FILE *platforms_file = PUSH_LT(lt, fopen(filename, "w"), fclose_lt);
92
93     if (platforms_file == NULL) {
94         log_fail("Could not open file '%s': %s\n", filename, strerror(errno));
95         RETURN_LT(lt, -1);
96     }
97
98     for (size_t i = 0; i < platforms->rects_size; ++i) {
99         if (fprintf(platforms_file, "%f %f %f %f\n",
100                     platforms->rects[i].x, platforms->rects[i].y,
101                     platforms->rects[i].w, platforms->rects[i].h) < 0) {
102             log_fail("Could not read %dth platform\n", i);
103             RETURN_LT(lt, -1);
104         }
105     }
106
107     RETURN_LT(lt, 0);
108 }
109
110 Solid_ref platforms_as_solid(Platforms *platforms)
111 {
112     Solid_ref ref = {
113         .tag = SOLID_PLATFORMS,
114         .ptr = (void*)platforms
115     };
116
117     return ref;
118 }
119
120 /* TODO(#450): platforms do not render their ids in debug mode */
121 int platforms_render(const Platforms *platforms,
122                      Camera *camera)
123 {
124     for (size_t i = 0; i < platforms->rects_size; ++i) {
125         if (camera_fill_rect(
126                 camera,
127                 platforms->rects[i],
128                 platforms->colors[i]) < 0) {
129             return -1;
130         }
131     }
132
133     return 0;
134 }
135
136 void platforms_touches_rect_sides(const Platforms *platforms,
137                                   Rect object,
138                                   int sides[RECT_SIDE_N])
139 {
140     trace_assert(platforms);
141
142     for (size_t i = 0; i < platforms->rects_size; ++i) {
143         rect_object_impact(object, platforms->rects[i], sides);
144     }
145 }