Mirai's Miscellaneous Misadventures

M35 / core / physics.c

// copyright 2022 zamfofex
// license: AGPLv3 or later

static unsigned char mimimi_ground_get(struct mimimi_ground *ground, int x, int y)
{
	if (x < 0) return 1;
	if (y < 0) return 1;
	if (x >= ground->width) return 1;
	if (y >= ground->height) return 1;
	return ground->tiles[x + y * ground->width];
}

static void mimimi_wall_physics(struct mimimi_physics_data *data)
{
	struct mimimi_ground *ground = data->ground;
	struct mimimi_position *position = data->position;
	struct mimimi_physics *physics = data->physics;
	
	int x0 = position->x;
	int y0 = position->y;
	int x1 = physics->width / 2;
	int y1 = physics->height;
	
	int top = (y0 - y1) / 128;
	int top2 = top - 1;
	int bottom = (y0 - 127) / 128;
	int bottom2 = bottom - 1;
	int left = (x0 - x1) / 128;
	int right = (x0 + x1) / 128;
	
	if (
		mimimi_ground_get(ground, left, bottom) != 0 &&
		mimimi_ground_get(ground, left, bottom2) != 0 ||
		mimimi_ground_get(ground, left, top) != 0 &&
		mimimi_ground_get(ground, left, top2) != 0
	)
	{
		if (physics->dx < 0) physics->dx = 0;
		position->x = (left + 1) * 128 + x1;
	}
	
	if (
		mimimi_ground_get(ground, right, bottom) != 0 &&
		mimimi_ground_get(ground, right, bottom2) != 0 ||
		mimimi_ground_get(ground, right, top) != 0 &&
		mimimi_ground_get(ground, right, top2) != 0
	)
	{
		if (physics->dx > 0) physics->dx = 0;
		position->x = right * 128 - x1 - 1;
	}
}

static void mimimi_slope_physics(struct mimimi_physics_data *data)
{
	struct mimimi_ground *ground = data->ground;
	struct mimimi_position *position = data->position;
	struct mimimi_physics *physics = data->physics;
	
	int x0 = position->x;
	int y0 = position->y;
	int x1 = physics->width / 2;
	int y1 = physics->height;
	
	int top = (y0 - y1) / 128;
	int bottom = (y0 - 127) / 128;
	int left = (x0 - x1) / 128;
	int right = (x0 + x1) / 128;
	
	if (mimimi_ground_get(ground, left, bottom) != 0)
	if (mimimi_ground_get(ground, left, top) == 0)
		position->y = bottom * 128;
	if (mimimi_ground_get(ground, right, bottom) != 0)
	if (mimimi_ground_get(ground, right, top) == 0)
		position->y = bottom * 128;
}

static void mimimi_ceiling_physics(struct mimimi_physics_data *data)
{
	struct mimimi_ground *ground = data->ground;
	struct mimimi_position *position = data->position;
	struct mimimi_physics *physics = data->physics;
	
	if (physics->dy > 0) return;
	
	int x0 = position->x;
	int y0 = position->y;
	int x1 = physics->width / 2;
	int y1 = physics->height;
	
	int top = (y0 - y1) / 128;
	int top2 = top - 1;
	int left = (x0 - x1) / 128;
	int right = (x0 + x1) / 128;
	
	if (mimimi_ground_get(ground, left, top) != 0 && mimimi_ground_get(ground, right, top) != 0)
	if (mimimi_ground_get(ground, left, top2) != 0 || mimimi_ground_get(ground, right, top2) != 0)
	{
		physics->dy = 0;
		position->y = (top + 1) * 128 + y1;
	}
}

static void mimimi_landing_physics(struct mimimi_physics_data *data)
{
	struct mimimi_ground *ground = data->ground;
	struct mimimi_position *position = data->position;
	struct mimimi_physics *physics = data->physics;
	
	int x0 = position->x;
	int y0 = position->y;
	int x1 = physics->width / 2;
	
	int bottom = y0 / 128;
	int left = (x0 - x1) / 128;
	int right = (x0 + x1) / 128;
	
	if (physics->dy < 0) return;
	
	if (mimimi_ground_get(ground, left, bottom) != 0 || mimimi_ground_get(ground, right, bottom) != 0)
	{
		physics->airborne = 0;
		physics->dy = 0;
		position->y = bottom * 128;
	}
}

static void mimimi_fall_physics(struct mimimi_physics_data *data)
{
	struct mimimi_ground *ground = data->ground;
	struct mimimi_position *position = data->position;
	struct mimimi_physics *physics = data->physics;
	
	int x0 = position->x;
	int y0 = position->y;
	int x1 = physics->width / 2;
	
	int bottom = y0 / 128;
	int center = x0 / 128;
	int left = (x0 - x1) / 128;
	int right = (x0 + x1) / 128;
	
	if (mimimi_ground_get(ground, left, bottom) == 0 && mimimi_ground_get(ground, right, bottom) == 0)
	{
		if (mimimi_ground_get(ground, center, (bottom + 1)) == 0)
			// fall
			physics->airborne = 1;
		else
			// step down
			position->y = (bottom + 1) * 128;
	}
}

static void mimimi_physics_dynamics(struct mimimi_physics_data *data)
{
	struct mimimi_position *position = data->position;
	struct mimimi_physics *physics = data->physics;
	
	position->x += physics->dx;
	position->y += physics->dy;
}

static void mimimi_ground_physics(struct mimimi_physics_data *data)
{
	struct mimimi_physics *physics = data->physics;
	
	physics->dx *= 5;
	physics->dx /= 6;
	physics->dy = 0;
	
	mimimi_physics_dynamics(data);
	
	mimimi_slope_physics(data);
	mimimi_wall_physics(data);
	mimimi_fall_physics(data);
}

static void mimimi_airborne_physics(struct mimimi_physics_data *data)
{
	struct mimimi_physics *physics = data->physics;
	
	physics->dx *= 17;
	physics->dx /= 18;
	physics->dy += physics->gravity;
	
	mimimi_physics_dynamics(data);
	
	mimimi_ceiling_physics(data);
	mimimi_wall_physics(data);
	mimimi_landing_physics(data);
}