Mirai's Miscellaneous Misadventures

M41 / core / controls.c

1// copyright 2023 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	
22	data->history->left <<= 1;
23	data->history->left |= data->chapter->left;
24	data->history->left &= 0xFFFF;
25	
26	data->history->right <<= 1;
27	data->history->right |= data->chapter->right;
28	data->history->right &= 0xFFFF;
29}
30
31static void mimimi_history_finish(void *data)
32{
33	struct mimimi_history_data *history_data = data;
34	mimimi_deallocate(history_data->allocator, history_data->behavior);
35	mimimi_deallocate(history_data->allocator, history_data);
36}
37
38struct mimimi_behavior *mimimi_history(struct mimimi_history *history, struct mimimi_chapter *chapter, struct mimimi_allocator *allocator)
39{
40	struct mimimi_history_data *data = mimimi_allocate(allocator, sizeof *data);
41	data->allocator = allocator;
42	data->history = history;
43	data->chapter = chapter;
44	
45	history->left = 0;
46	history->right = 0;
47	
48	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
49	data->behavior->behave = &mimimi_history_behave;
50	data->behavior->finish = &mimimi_history_finish;
51	data->behavior->data = data;
52	
53	return data->behavior;
54}
55
56struct mimimi_controls_data
57{
58	struct mimimi_allocator *allocator;
59	struct mimimi_behavior *behavior;
60	struct mimimi_controls *controls;
61	struct mimimi_walk *walk;
62	struct mimimi_history *history;
63};
64
65static unsigned char mimimi_count_oscillations(unsigned int history)
66{
67	unsigned char count = 0;
68	unsigned char prev = history&1;
69	for (int i = 0 ; i < 16 ; i++)
70	{
71		if ((history&1) != prev) count++;
72		prev = history&1;
73		history >>= 1;
74	}
75	return count;
76}
77
78static void mimimi_control(void *data)
79{
80	struct mimimi_controls_data *controls_data = data;
81	
82	struct mimimi_walk *walk = controls_data->walk;
83	struct mimimi_history *history = controls_data->history;
84	
85	struct mimimi_behavior *jump = controls_data->controls->jump;
86	
87	unsigned char left_oscillations = mimimi_count_oscillations(history->left);
88	unsigned char right_oscillations = mimimi_count_oscillations(history->right);
89	
90	switch (walk->direction)
91	{
92	case 0:
93		if ((history->left&1) != 0)
94		{
95			walk->direction = 1;
96			if (left_oscillations > 1 && (history->left&2) == 0)
97				(*jump->behave)(jump->data);
98		}
99		if ((history->right&1) != 0)
100		{
101			walk->direction = 2;
102			if (right_oscillations > 1 && (history->right&2) == 0)
103				(*jump->behave)(jump->data);
104		}
105		break;
106	case 1:
107		if ((history->left&1) == 0)
108			walk->direction = 0;
109		break;
110	case 2:
111		if ((history->right&1) == 0)
112			walk->direction = 0;
113		break;
114	}
115}
116
117static void mimimi_controls_finish(void *data)
118{
119	struct mimimi_controls_data *controls_data = data;
120	mimimi_deallocate(controls_data->allocator, controls_data->behavior);
121	mimimi_deallocate(controls_data->allocator, controls_data);
122}
123
124struct mimimi_behavior *mimimi_controls(struct mimimi_controls *controls, struct mimimi_walk *walk, struct mimimi_history *history, struct mimimi_allocator *allocator)
125{
126	struct mimimi_controls_data *data = mimimi_allocate(allocator, sizeof *data);
127	data->allocator = allocator;
128	data->controls = controls;
129	data->walk = walk;
130	data->history = history;
131	
132	controls->jump = mimimi_noop;
133	
134	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
135	data->behavior->behave = &mimimi_control;
136	data->behavior->finish = &mimimi_controls_finish;
137	data->behavior->data = data;
138	
139	return data->behavior;
140}
141
142struct mimimi_stationary
143{
144	struct mimimi_allocator *allocator;
145	struct mimimi_behavior *behavior;
146	int *direction;
147	int *position;
148	int *target;
149};
150
151static void mimimi_stationary_behave(void *data)
152{
153	struct mimimi_stationary *stationary = data;
154	if (*stationary->position < *stationary->target)
155		*stationary->direction = 1;
156	else
157		*stationary->direction = 2;
158}
159
160static void mimimi_stationary_finish(void *data)
161{
162	struct mimimi_stationary *stationary = data;
163	mimimi_deallocate(stationary->allocator, stationary->behavior);
164	mimimi_deallocate(stationary->allocator, stationary);
165}
166
167struct mimimi_behavior *mimimi_stationary(int *direction, int *position, int *target, struct mimimi_allocator *allocator)
168{
169	struct mimimi_stationary *data = mimimi_allocate(allocator, sizeof *data);
170	data->allocator = allocator;
171	data->direction = direction;
172	data->position = position;
173	data->target = target;
174	
175	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
176	data->behavior->behave = &mimimi_stationary_behave;
177	data->behavior->finish = &mimimi_stationary_finish;
178	data->behavior->data = data;
179	
180	return data->behavior;
181}