Mirai's Miscellaneous Misadventures

M18 / core / displays.c

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

#include "appearances.h"

#include <mimimi/allocators.h>
#include <mimimi/behaviors.h>
#include <mimimi/sprites.h>
#include <mimimi/geometry.h>
#include <mimimi/engines.h>
#include <mimimi/chapters.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_appearance *appearance;
	unsigned char animation_time;
	unsigned char direction;
};

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

static void mimimi_display_behave(void *data)
{
	struct mimimi_display *display = data;
	struct mimimi_sprite *sprite = display->sprite;
	struct mimimi_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;
	
	int dx;
	int dy = physics->dy;
	
	if (walk->direction != 0) display->direction = walk->direction;
	
	struct mimimi_animation_set *animations;
	
	if (display->direction == 1)
	{
		dx = -physics->dx;
		animations = &appearance->left;
	}
	if (display->direction == 2)
	{
		dx = physics->dx;
		animations = &appearance->right;
	}
	
	if (dx > 31) dx = 31;
	if (dx < 0) dx = 0;
	if (dy < 0) dy = 0;
	
	struct mimimi_animation *animation;
	
	if (life->knocked_time == 0)
	{
		animation = animations->standing + dx * mimimi_animation_count / 32;
		display->animation_time += dx / 4;
	}
	else
	{
		animation = &animations->knocked;
		if (dy == 0) display->animation_time = 0;
		else display->animation_time += dy / 8;
	}
	struct mimimi_image *image = &animation->images[display->animation_time * mimimi_image_count / 256].image;
	int y = 0;
	if (life->knocked_time != 0) y = image->height * 4 - 32;
	
	mimimi_camera_stamp(display->engine, display->camera, position->x, position->y + y, 0, image);
}

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

struct mimimi_behavior *mimimi_display(struct mimimi_engine *engine, struct mimimi_position *camera, struct mimimi_sprite *sprite, struct mimimi_appearance *appearance, struct mimimi_allocator *allocator)
{
	struct mimimi_display *display = (*allocator->allocate)(sizeof *display);
	display->allocator = allocator;
	display->engine = engine;
	display->camera = camera;
	display->sprite = sprite;
	display->appearance = appearance;
	
	display->animation_time = 0;
	display->direction = 1;
	
	display->behavior = (*allocator->allocate)(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;
	struct mimimi_image *image;
	struct mimimi_position *camera;
	struct mimimi_engine *engine;
	int offset;
};

static void mimimi_background_behave(void *data)
{
	struct mimimi_background *background_data = data;
	mimimi_camera_stamp(background_data->engine, background_data->camera, background_data->image->width * 4, background_data->image->height * 8 - 7, background_data->offset, background_data->image);
}

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

struct mimimi_behavior *mimimi_background(struct mimimi_engine *engine, struct mimimi_position *camera, struct mimimi_image *image, int offset, struct mimimi_allocator *allocator)
{
	struct mimimi_background *data = (*allocator->allocate)(sizeof *data);
	data->allocator = allocator;
	data->image = image;
	data->camera = camera;
	data->engine = engine;
	data->offset = offset;
	
	data->behavior = (*allocator->allocate)(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;
	struct mimimi_image *image;
	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->image);
}

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

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