Mirai's Miscellaneous Misadventures

M32 / core / controls.c

1// copyright 2022 zamfofex
2// license: AGPLv3 or later
3
4#include <mimimi/controls.h>
5#include <mimimi/behaviors.h>
6#include <mimimi/allocators.h>
7#include <mimimi/sprites.h>
8#include <mimimi/chapters.h>
9
10struct mimimi_history_data
11{
12	struct mimimi_allocator *allocator;
13	struct mimimi_behavior *behavior;
14	struct mimimi_history *history;
15	struct mimimi_chapter *chapter;
16};
17
18static void mimimi_history_behave(void *data0)
19{
20	struct mimimi_history_data *data = data0;
21	data->history->left <<= 1;
22	data->history->left |= data->chapter->left;
23	data->history->right <<= 1;
24	data->history->right |= data->chapter->right;
25}
26
27static void mimimi_history_finish(void *data)
28{
29	struct mimimi_history_data *history_data = data;
30	mimimi_deallocate(history_data->allocator,history_data->behavior);
31	mimimi_deallocate(history_data->allocator,history_data);
32}
33
34struct mimimi_behavior *mimimi_history(struct mimimi_history *history, struct mimimi_chapter *chapter, struct mimimi_allocator *allocator)
35{
36	struct mimimi_history_data *data = mimimi_allocate(allocator, sizeof *data);
37	data->allocator = allocator;
38	data->history = history;
39	data->chapter = chapter;
40	
41	history->left = 0;
42	history->right = 0;
43	
44	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
45	data->behavior->behave = &mimimi_history_behave;
46	data->behavior->finish = &mimimi_history_finish;
47	data->behavior->data = data;
48	
49	return data->behavior;
50}
51
52struct mimimi_controls_data
53{
54	struct mimimi_allocator *allocator;
55	struct mimimi_behavior *behavior;
56	struct mimimi_controls *controls;
57	struct mimimi_walk *walk;
58	struct mimimi_history *history;
59};
60
61static unsigned char mimimi_count_oscillations(unsigned int history)
62{
63	unsigned char count = 0;
64	unsigned char prev = history&1;
65	for (int i = 0 ; i < 16 ; i++)
66	{
67		if ((history&1) != prev) count++;
68		prev = history&1;
69		history >>= 1;
70	}
71	return count;
72}
73
74static void mimimi_control(void *data)
75{
76	struct mimimi_controls_data *controls_data = data;
77	
78	struct mimimi_walk *walk = controls_data->walk;
79	struct mimimi_history *history = controls_data->history;
80	
81	struct mimimi_behavior *jump = controls_data->controls->jump;
82	
83	unsigned char left_oscillations = mimimi_count_oscillations(history->left);
84	unsigned char right_oscillations = mimimi_count_oscillations(history->right);
85	
86	switch (walk->direction)
87	{
88	case 0:
89		if ((history->left&1) != 0)
90		{
91			walk->direction = 1;
92			if (left_oscillations > 1 && (history->left&2) == 0)
93				(*jump->behave)(jump->data);
94		}
95		if ((history->right&1) != 0)
96		{
97			walk->direction = 2;
98			if (right_oscillations > 1 && (history->right&2) == 0)
99				(*jump->behave)(jump->data);
100		}
101		break;
102	case 1:
103		if ((history->left&1) == 0)
104			walk->direction = 0;
105		break;
106	case 2:
107		if ((history->right&1) == 0)
108			walk->direction = 0;
109		break;
110	}
111}
112
113static void mimimi_controls_finish(void *data)
114{
115	struct mimimi_controls_data *controls_data = data;
116	mimimi_deallocate(controls_data->allocator, controls_data->behavior);
117	mimimi_deallocate(controls_data->allocator, controls_data);
118}
119
120struct mimimi_behavior *mimimi_controls(struct mimimi_controls *controls, struct mimimi_walk *walk, struct mimimi_history *history, struct mimimi_allocator *allocator)
121{
122	struct mimimi_controls_data *data = mimimi_allocate(allocator, sizeof *data);
123	data->allocator = allocator;
124	data->controls = controls;
125	data->walk = walk;
126	data->history = history;
127	
128	controls->jump = mimimi_noop;
129	
130	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
131	data->behavior->behave = &mimimi_control;
132	data->behavior->finish = &mimimi_controls_finish;
133	data->behavior->data = data;
134	
135	return data->behavior;
136}
137
138struct mimimi_jump_data
139{
140	struct mimimi_allocator *allocator;
141	struct mimimi_behavior *behavior;
142	struct mimimi_jump *jump;
143	struct mimimi_physics *physics;
144};
145
146static void mimimi_jump_behave(void *data)
147{
148	struct mimimi_jump_data *jump_data = data;
149	jump_data->physics->airborne = 1;
150	jump_data->physics->dy = -jump_data->jump->strength;
151}
152
153static void mimimi_jump_finish(void *data)
154{
155	struct mimimi_jump_data *jump_data = data;
156	mimimi_deallocate(jump_data->allocator, jump_data->behavior);
157	mimimi_deallocate(jump_data->allocator, jump_data);
158}
159
160struct mimimi_behavior *mimimi_jump(struct mimimi_jump *jump, struct mimimi_physics *physics, struct mimimi_allocator *allocator)
161{
162	struct mimimi_jump_data *data = mimimi_allocate(allocator, sizeof *data);
163	data->allocator = allocator;
164	data->jump = jump;
165	data->physics = physics;
166	
167	jump->strength = 56;
168	
169	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
170	data->behavior->behave = &mimimi_jump_behave;
171	data->behavior->finish = &mimimi_jump_finish;
172	data->behavior->data = data;
173	
174	return data->behavior;
175}
176
177struct mimimi_dash_data
178{
179	struct mimimi_allocator *allocator;
180	struct mimimi_behavior *behavior;
181	struct mimimi_dash *dash;
182	struct mimimi_physics *physics;
183	struct mimimi_walk *walk;
184};
185
186static void mimimi_dash_behave(void *data)
187{
188	struct mimimi_dash_data *dash_data = data;
189	if (dash_data->walk->direction == 1)
190		dash_data->physics->dx -= dash_data->dash->x_strength;
191	if (dash_data->walk->direction == 2)
192		dash_data->physics->dx += dash_data->dash->x_strength;
193	dash_data->physics->dy -= dash_data->dash->y_strength;
194}
195
196static void mimimi_dash_finish(void *data)
197{
198	struct mimimi_dash_data *dash_data = data;
199	mimimi_deallocate(dash_data->allocator, dash_data->behavior);
200	mimimi_deallocate(dash_data->allocator, dash_data);
201}
202
203struct mimimi_behavior *mimimi_dash(struct mimimi_dash *dash, struct mimimi_physics *physics, struct mimimi_walk *walk, struct mimimi_allocator *allocator)
204{
205	struct mimimi_dash_data *data = mimimi_allocate(allocator, sizeof *data);
206	data->allocator = allocator;
207	data->dash = dash;
208	data->physics = physics;
209	data->walk = walk;
210	
211	dash->x_strength = 32;
212	dash->y_strength = 16;
213	
214	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
215	data->behavior->behave = &mimimi_dash_behave;
216	data->behavior->finish = &mimimi_dash_finish;
217	data->behavior->data = data;
218	
219	return data->behavior;
220}
221
222struct mimimi_stationary
223{
224	struct mimimi_allocator *allocator;
225	struct mimimi_behavior *behavior;
226	int *direction;
227	int *position;
228	int *target;
229};
230
231static void mimimi_stationary_behave(void *data)
232{
233	struct mimimi_stationary *stationary = data;
234	if (*stationary->position > *stationary->target)
235		*stationary->direction = 1;
236	else
237		*stationary->direction = 2;
238}
239
240static void mimimi_stationary_finish(void *data)
241{
242	struct mimimi_stationary *stationary = data;
243	mimimi_deallocate(stationary->allocator, stationary->behavior);
244	mimimi_deallocate(stationary->allocator, stationary);
245}
246
247struct mimimi_behavior *mimimi_stationary(int *direction, int *position, int *target, struct mimimi_allocator *allocator)
248{
249	struct mimimi_stationary *data = mimimi_allocate(allocator, sizeof *data);
250	data->allocator = allocator;
251	data->direction = direction;
252	data->position = position;
253	data->target = target;
254	
255	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
256	data->behavior->behave = &mimimi_stationary_behave;
257	data->behavior->finish = &mimimi_stationary_finish;
258	data->behavior->data = data;
259	
260	return data->behavior;
261}