Mirai's Miscellaneous Misadventures

M41 / core / effects.c

1// copyright 2023 zamfofex
2// license: AGPLv3 or later
3
4#include <mimimi/ground.h>
5#include <mimimi/behaviors.h>
6#include <mimimi/sprites.h>
7#include <mimimi/allocators.h>
8#include <mimimi/geometry.h>
9#include <mimimi/compound-behaviors.h>
10
11struct mimimi_conveyor
12{
13	struct mimimi_sprite *sprite;
14	struct mimimi_ground *ground;
15	unsigned char which;
16	int speed;
17	unsigned char was_airborne;
18};
19
20static void mimimi_conveyor_behave(void *data)
21{
22	struct mimimi_conveyor *conveyor_data = data;
23	struct mimimi_sprite *sprite = conveyor_data->sprite;
24	struct mimimi_ground *ground = conveyor_data->ground;
25	unsigned char was_airborne = conveyor_data->was_airborne;
26	conveyor_data->was_airborne = sprite->physics->airborne;
27	
28	if (sprite->physics->airborne != 0)
29	{
30		if (was_airborne == 0)
31			sprite->physics->dx += conveyor_data->speed;
32		return;
33	}
34	
35	int x1 = (sprite->position->x - sprite->physics->width / 2) / 128;
36	int x2 = (sprite->position->x + sprite->physics->width / 2) / 128;
37	int y = (sprite->position->y + 64) / 128;
38	
39	if (mimimi_ground_tile(ground, x1, y) == conveyor_data->which || mimimi_ground_tile(ground, x2, y) == conveyor_data->which)
40		sprite->position->x += conveyor_data->speed;
41}
42
43struct mimimi_behavior *mimimi_conveyor(struct mimimi_sprite *sprite, struct mimimi_ground *ground, unsigned char which, int speed, struct mimimi_allocator *allocator)
44{
45	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
46	
47	struct mimimi_conveyor *conveyor = mimimi_compound_allocate(compound, sizeof *conveyor, allocator);
48	conveyor->sprite = sprite;
49	conveyor->ground = ground;
50	conveyor->which = which;
51	conveyor->speed = speed;
52	conveyor->was_airborne = sprite->physics->airborne;
53	
54	mimimi_compound(compound, mimimi_function(conveyor, &mimimi_conveyor_behave, allocator));
55	
56	return compound;
57}
58
59struct mimimi_transformed_physics
60{
61	struct mimimi_physics *physics;
62	struct mimimi_position *position;
63	struct mimimi_ground *ground;
64	struct mimimi_physics *other;
65	struct mimimi_behavior *behavior;
66	struct mimimi_position *transform;
67	struct mimimi_position previous;
68	struct mimimi_position other_position;
69	unsigned char was_airborne;
70};
71
72static void mimimi_transformed_physics_behave(void *data)
73{
74	struct mimimi_transformed_physics *physics = data;
75	
76	int dx = physics->transform->x - physics->previous.x;
77	int dy = physics->transform->y - physics->previous.y;
78	physics->previous = *physics->transform;
79	
80	unsigned char was_airborne = physics->was_airborne;
81	physics->was_airborne = physics->other->airborne;
82	
83	physics->other->dx = physics->physics->dx;
84	physics->other->dy = physics->physics->dy;
85	physics->other->width = physics->physics->width;
86	physics->other->height = physics->physics->height;
87	physics->other->gravity = 0;
88	
89	physics->other_position = *physics->position;
90	physics->other_position.x -= physics->transform->x;
91	physics->other_position.y -= physics->transform->y;
92	
93	if (physics->other->airborne == 0)
94	{
95		physics->other_position.x += dx;
96		physics->other_position.y += dy;
97	}
98	
99	if (physics->physics->airborne != 0) physics->other->airborne = 1;
100	
101	(*physics->behavior->behave)(physics->behavior->data);
102	
103	if (physics->other->airborne == 0) physics->physics->airborne = 0;
104	
105	*physics->position = physics->other_position;
106	physics->position->x += physics->transform->x;
107	physics->position->y += physics->transform->y;
108	
109	physics->physics->dx = physics->other->dx;
110	physics->physics->dy = physics->other->dy;
111	
112	if (physics->other->airborne != 0 && was_airborne == 0)
113	{
114		physics->physics->dx += dx;
115		physics->physics->dy += dy;
116	}
117}
118
119struct mimimi_behavior *mimimi_positioned_physics(struct mimimi_physics *other, struct mimimi_position *position, struct mimimi_ground *ground, struct mimimi_position *transform, struct mimimi_allocator *allocator)
120{
121	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
122	
123	struct mimimi_transformed_physics *physics = mimimi_compound_allocate(compound, sizeof *physics, allocator);
124	physics->physics = other;
125	physics->position = position;
126	physics->ground = ground;
127	physics->other = mimimi_compound_allocate(compound, sizeof *physics->other, allocator);
128	physics->behavior = mimimi_collision_physics(physics->other, &physics->other_position, ground, allocator);
129	physics->transform = transform;
130	physics->previous = *transform;
131	physics->was_airborne = other->airborne;
132	
133	mimimi_compound(compound, mimimi_function(physics, &mimimi_transformed_physics_behave, allocator));
134	mimimi_compound(compound, mimimi_finalizer(physics->behavior->data, physics->behavior->finish, allocator));
135	
136	return compound;
137}
138
139struct mimimi_trampoline
140{
141	struct mimimi_sprite *sprite;
142	struct mimimi_ground *ground;
143	unsigned char which;
144	int restitution;
145	int dy;
146};
147
148static void mimimi_trampoline_behave(void *data)
149{
150	struct mimimi_trampoline *trampoline_data = data;
151	struct mimimi_sprite *sprite = trampoline_data->sprite;
152	struct mimimi_ground *ground = trampoline_data->ground;
153	int dy = trampoline_data->dy;
154	trampoline_data->dy = 0;
155	
156	if (sprite->physics->airborne != 0)
157	{
158		trampoline_data->dy = sprite->physics->dy;
159		return;
160	}
161	
162	if (dy == 0) return;
163	
164	int x1 = (sprite->position->x - sprite->physics->width / 2) / 128;
165	int x2 = (sprite->position->x + sprite->physics->width / 2) / 128;
166	int y = (sprite->position->y + 64) / 128;
167	
168	if (mimimi_ground_tile(ground, x1, y) != trampoline_data->which) return;
169	if (mimimi_ground_tile(ground, x2, y) != trampoline_data->which) return;
170	
171	sprite->physics->airborne = 1;
172	sprite->physics->dy -= dy * trampoline_data->restitution / 256;
173}
174
175struct mimimi_behavior *mimimi_trampoline(struct mimimi_sprite *sprite, struct mimimi_ground *ground, unsigned char which, int restitution, struct mimimi_allocator *allocator)
176{
177	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
178	
179	struct mimimi_trampoline *trampoline = mimimi_compound_allocate(compound, sizeof *trampoline, allocator);
180	trampoline->sprite = sprite;
181	trampoline->ground = ground;
182	trampoline->which = which;
183	trampoline->restitution = restitution;
184	trampoline->dy = sprite->physics->dy;
185	
186	mimimi_compound(compound, mimimi_function(trampoline, &mimimi_trampoline_behave, allocator));
187	
188	return compound;
189}