Mirai's Miscellaneous Misadventures

M35 / core / displays.c

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

#include <mimimi/allocators.h>
#include <mimimi/behaviors.h>
#include <mimimi/sprites.h>
#include <mimimi/geometry.h>
#include <mimimi/engines.h>
#include <mimimi/chapters.h>
#include <mimimi/assets.h>
#include <mimimi/animations.h>
#include <mimimi/appearances.h>
#include <mimimi/video.h>

struct mimimi_display
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_engine *engine;
	struct mimimi_position *camera;
	struct mimimi_sprite *sprite;
	struct mimimi_video_appearance *appearance;
	unsigned char animation_time;
	int *direction;
	int x;
	int y;
};

static void mimimi_camera_stamp(struct mimimi_engine *engine, struct mimimi_position *camera, int x, int y, int z, void *texture)
{
	z += 8;
	if (z <= 0) return;
	
	x -= camera->x;
	x /= z;
	x += engine->size->width / 2;
	
	y -= camera->y;
	y /= z;
	y += engine->size->height / 2;
	
	(*engine->stamp)(engine->data, x, y, texture);
}

static void mimimi_display_behave(void *data)
{
	struct mimimi_display *display = data;
	struct mimimi_sprite *sprite = display->sprite;
	struct mimimi_video_appearance *appearance = display->appearance;
	
	struct mimimi_position *position = sprite->position;
	struct mimimi_physics *physics = sprite->physics;
	struct mimimi_life *life = sprite->life;
	struct mimimi_walk *walk = sprite->walk;
	
	if (walk->direction != 0) *display->direction = walk->direction;
	
	int dx;
	int dy = physics->dy;
	
	struct mimimi_video_set *videos;
	
	if (*display->direction == 1)
	{
		dx = -physics->dx;
		videos = &appearance->left;
	}
	if (*display->direction == 2)
	{
		dx = physics->dx;
		videos = &appearance->right;
	}
	
	if (dx > 31) dx = 31;
	if (dx < 0) dx = 0;
	if (dy < 0) dy = 0;
	
	struct mimimi_video *video;
	
	int x = -8 * display->x;
	int y = -8 * display->y;
	
	if (life->knocked_time == 0)
	{
		if (physics->airborne != 0)
		{
			void *texture = videos->jumping->textures[dx * videos->jumping->count / 32];
			mimimi_camera_stamp(display->engine, display->camera, position->x + x, position->y + y, 0, texture);
			return;
		}
		
		video = videos->standing + dx * videos->standing_video_count / 32;
		display->animation_time += dx / 4;
	}
	else
	{
		if (physics->airborne == 0)
			video = videos->knocked,
			y += 128;
		else
			video = videos->falling;
		
		display->animation_time += dy / 8;
	}
	
	void *texture = video->textures[display->animation_time * video->count / 256];
	mimimi_camera_stamp(display->engine, display->camera, position->x + x, position->y + y, 0, texture);
}

static void mimimi_display_finish(void *data)
{
	struct mimimi_display *display = data;
	mimimi_deallocate(display->allocator, display->behavior);
	mimimi_deallocate(display->allocator, display);
}

struct mimimi_behavior *mimimi_display(struct mimimi_engine *engine, struct mimimi_position *camera, struct mimimi_sprite *sprite, struct mimimi_video_appearance *appearance, int *direction, int x, int y, struct mimimi_allocator *allocator)
{
	struct mimimi_display *display = mimimi_allocate(allocator, sizeof *display);
	display->allocator = allocator;
	display->engine = engine;
	display->camera = camera;
	display->sprite = sprite;
	display->appearance = appearance;
	display->x = x;
	display->y = y;
	
	display->animation_time = 0;
	display->direction = direction;
	*direction = 1;
	
	display->behavior = mimimi_allocate(allocator, sizeof *display->behavior);
	display->behavior->behave = &mimimi_display_behave;
	display->behavior->finish = &mimimi_display_finish;
	display->behavior->data = display;
	
	return display->behavior;
}

struct mimimi_background
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	void *texture;
	struct mimimi_position *camera;
	struct mimimi_engine *engine;
	int x, y, z;
};

static void mimimi_background_behave(void *data)
{
	struct mimimi_background *background_data = data;
	mimimi_camera_stamp(background_data->engine, background_data->camera, background_data->x, background_data->y - 7, background_data->z, background_data->texture);
}

static void mimimi_background_finish(void *data)
{
	struct mimimi_background *background_data = data;
	mimimi_deallocate(background_data->allocator, background_data->behavior);
	mimimi_deallocate(background_data->allocator, background_data);
}

struct mimimi_behavior *mimimi_background(struct mimimi_engine *engine, struct mimimi_position *camera, void *texture, int x, int y, int z, struct mimimi_allocator *allocator)
{
	struct mimimi_background *data = mimimi_allocate(allocator, sizeof *data);
	data->allocator = allocator;
	data->texture = texture;
	data->camera = camera;
	data->engine = engine;
	data->x = x;
	data->y = y;
	data->z = z;
	
	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
	data->behavior->behave = &mimimi_background_behave;
	data->behavior->finish = &mimimi_background_finish;
	data->behavior->data = data;
	
	return data->behavior;
}

struct mimimi_overlay
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_engine *engine;
	void *texture;
	int x;
	int y;
};

static void mimimi_overlay_behave(void *data)
{
	struct mimimi_overlay *overlay_data = data;
	struct mimimi_engine *engine = overlay_data->engine;
	(*engine->stamp)(engine->data, overlay_data->x, overlay_data->y, overlay_data->texture);
}

static void mimimi_overlay_finish(void *data)
{
	struct mimimi_background *overlay_data = data;
	mimimi_deallocate(overlay_data->allocator, overlay_data->behavior);
	mimimi_deallocate(overlay_data->allocator, overlay_data);
}

struct mimimi_behavior *mimimi_overlay(struct mimimi_engine *engine, void *texture, int x, int y, struct mimimi_allocator *allocator)
{
	struct mimimi_overlay *data = mimimi_allocate(allocator, sizeof *data);
	data->allocator = allocator;
	data->engine = engine;
	data->texture = texture;
	data->x = x;
	data->y = y;
	
	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
	data->behavior->behave = &mimimi_overlay_behave;
	data->behavior->finish = &mimimi_overlay_finish;
	data->behavior->data = data;
	
	return data->behavior;
}