Mirai's Miscellaneous Misadventures

M47 / chapters / chapter-I / setup.c

/* license: AGPLv3 or later */
/* copyright 2023 zamfofex */

#include <mimimi-chapters.h>

#include "ground.c"
#include "background.c"
#include "foreground.c"

static void mimimi_chapter_I_video_set(struct mimimi_test_video_set *tset, struct mimimi_video_set *set)
{
	static int video_count = 8;
	static int image_count = 8;
	static int width = 48;
	static int height = 48;
	
	int i, j, k;
	struct mimimi_video *videos, *standing, *knocked, *falling, *jumping;
	struct mimimi_image *images, *image;
	unsigned char *colors;
	void **textures;
	
	videos = tset->videos;
	images = tset->images;
	colors = tset->colors;
	textures = tset->textures;
	
	set->standing = videos;
	set->standing_video_count = video_count;
	videos += video_count;
	
	set->jumping = videos;
	set->jumping_video_count = video_count;
	videos += video_count;
	
	for (i = 0 ; i < video_count ; i++)
	{
		standing = set->standing + i;
		standing->count = image_count;
		standing->images = images;
		images += image_count;
		standing->textures = textures;
		textures += image_count;
		
		for (j = 0 ; j < image_count ; j++)
		{
			image = standing->images + j;
			image->width = width;
			image->height = height;
			image->colors = colors;
			colors += width * height;
			for (k = 0 ; k < width * height ; k++) image->colors[k] = 0;
		}
		
		jumping = set->jumping + i;
		jumping->count = image_count;
		jumping->images = images;
		images += image_count;
		jumping->textures = textures;
		textures += image_count;
		
		for (j = 0 ; j < image_count ; j++)
		{
			image = jumping->images + j;
			image->width = width;
			image->height = height;
			image->colors = colors;
			colors += width * height;
			for (k = 0 ; k < width * height ; k++) image->colors[k] = 0;
		}
	}
	
	knocked = videos++;
	knocked->count = 1;
	knocked->images = images++;
	knocked->images[0].width = width;
	knocked->images[0].height = height;
	knocked->images[0].colors = colors;
	knocked->textures = textures++;
	colors += width * height;
	for (i = 0 ; i < width * height ; i++) knocked->images[0].colors[i] = 0;
	
	falling = videos++;
	falling->count = 1;
	falling->images = images++;
	falling->images[0].width = width;
	falling->images[0].height = height;
	falling->images[0].colors = colors;
	colors += width * height;
	falling->textures = textures++;
	for (i = 0 ; i < width * height ; i++) falling->images[0].colors[i] = 0;
	
	set->knocked = knocked;
	set->falling = falling;
}

static void mimimi_chapter_I_appearance(struct mimimi_test_sprite *sprite, struct mimimi_engine *engine)
{
	mimimi_chapter_I_video_set(&sprite->left, &sprite->appearance.left);
	mimimi_chapter_I_video_set(&sprite->right, &sprite->appearance.right);
	
	mimimi_appearance(&sprite->appearance, sprite->model, 24, 37);
	mimimi_prepare_appearance(&sprite->appearance, engine);
}

static void mimimi_chapter_I_origin(struct mimimi_ground *ground, struct mimimi_position *position)
{
	for (position->y = 0 ; position->y < ground->height ; position->y++)
	for (position->x = 0 ; position->x < ground->width ; position->x++)
	{
		if (ground->tiles[position->x + position->y * ground->width] == 2)
			return;
	}
}

static void mimimi_chapter_I_sprite(struct mimimi_test_sprite *sprite, struct mimimi_model *model, struct mimimi_chapter_I *chapter)
{
	sprite->model = model;
	sprite->display.camera = &chapter->clamped_camera.output;
	sprite->display.sprite = &sprite->sprite;
	sprite->display.appearance = &sprite->appearance;
	sprite->display.animation_time = 0;
	sprite->display.direction = 1;
	sprite->display.width = 24;
	sprite->display.height = 48;
	mimimi_sprite(&sprite->sprite, mimimi_chapter_I_ground, 0, 0, 80, 250);
	mimimi_chapter_I_appearance(sprite, chapter->engine);
}

static void mimimi_chapter_I_player_tick(struct mimimi_chapter_I *chapter)
{
	mimimi_controls_tick(&chapter->player.sprite.walk, &chapter->history, &mimimi_jump, &chapter->player.sprite);
	mimimi_sprite_tick(&chapter->player.sprite);
}

static void mimimi_chapter_I_unpack_bits(int size, unsigned char *unpacked, unsigned char *packed)
{
	int i, j, k, n;
	
	i = 0;
	j = 0;
	
	while (j < size)
	{
		n = packed[i++];
		if (n == 128) continue;
		if (n > 128) n -= 256;
		
		if (n > 0)
		{
			for (k = 0 ; k <= n ; k++)
				unpacked[j++] = packed[i++];
		}
		else
		{
			for (k = 0 ; k <= -n ; k++)
				unpacked[j++] = packed[i];
			i++;
		}
	}
}

static void mimimi_chapter_I_stamp(struct mimimi_image *image, struct mimimi_image *source, int x, int y)
{
	int x0, y0;
	for (y0 = 0 ; y0 < source->height ; y0++)
	for (x0 = 0 ; x0 < source->width ; x0++)
		image->colors[(x0 + x) + (y0 + y) * image->width] = source->colors[x0 + y0 * source->width];
}

static void mimimi_chapter_I_background(struct mimimi_chapter_I *chapter)
{
	static unsigned char colors[] = {6, 2, 2};
	
	int x, y;
	unsigned char color;
	int size;
	
	chapter->background_image.colors = chapter->background_colors;
	chapter->background_image.width = mimimi_chapter_I_ground->width * 16;
	chapter->background_image.height = mimimi_chapter_I_ground->height * 16;
	
	for (y = 0 ; y < chapter->background_image.height ; y++)
	for (x = 0 ; x < chapter->background_image.width ; x++)
	{
		color = colors[mimimi_ground_tile(mimimi_chapter_I_ground, x / 16, y / 16)];
		chapter->background_image.colors[x + y * chapter->background_image.width] = color;
	}
	
	chapter->custom_background.colors = chapter->colors;
	chapter->custom_background.width = mimimi_chapter_I_background_width;
	chapter->custom_background.height = mimimi_chapter_I_background_height;
	size = chapter->custom_background.width * chapter->custom_background.height;
	
	mimimi_chapter_I_unpack_bits(size, chapter->colors, mimimi_chapter_I_background_packed);
	
	mimimi_chapter_I_stamp(&chapter->background_image, &chapter->custom_background, (chapter->origin.x - 36) * 16 + 5, (chapter->origin.y - 10) * 16);
	
	chapter->background.texture = (*chapter->engine->texture)(chapter->engine->data, &chapter->background_image);
	chapter->background.camera = &chapter->clamped_camera.output;
	chapter->background.z = 0;
}

static void mimimi_chapter_I_foreground(struct mimimi_chapter_I *chapter)
{
	int size;
	
	chapter->foreground_image.colors = chapter->colors;
	chapter->foreground_image.width = mimimi_chapter_I_foreground_width;
	chapter->foreground_image.height = mimimi_chapter_I_foreground_height;
	size = chapter->foreground_image.width * chapter->foreground_image.height;
	
	mimimi_chapter_I_unpack_bits(size, chapter->colors, mimimi_chapter_I_foreground_packed);
	
	chapter->foreground.texture = (*chapter->engine->texture)(chapter->engine->data, &chapter->foreground_image);
	chapter->foreground.camera = &chapter->clamped_camera.output;
	chapter->foreground.z = 0;
}

static void mimimi_chapter_I_camera(struct mimimi_chapter_I *chapter)
{
	static struct mimimi_clamped_camera_threshold thresholds[] =
	{
		{-166, 0, 0},
		{-134, -51, -5},
		{-35, -13, 5},
		{8, 2, 2},
		{1000, 1, 1},
	};
	
	chapter->clamped_camera.position = &chapter->player.sprite.position;
	chapter->clamped_camera.input = &chapter->camera;
	chapter->clamped_camera.thresholds = thresholds;
	chapter->clamped_camera.count = sizeof thresholds / sizeof *thresholds;
}

static void mimimi_chapter_I_offset(struct mimimi_chapter_I *chapter)
{
	static struct mimimi_offset_threshold thresholds[] =
	{
		{-134, {-29824, -768}},
		{-35, {-12800, 2432}},
		{8, {0, 0}},
	};
	
	chapter->offset.sprite = &chapter->player.sprite;
	chapter->offset.thresholds = thresholds;
	chapter->offset.count = sizeof thresholds / sizeof *thresholds;
}

static void mimimi_chapter_I_background_tick(struct mimimi_chapter_I *chapter)
{
	chapter->background.x = chapter->player.sprite.offset.x;
	chapter->background.y = chapter->player.sprite.offset.y;
	mimimi_background_tick(&chapter->background, chapter->engine);
}

static void mimimi_chapter_I_foreground_tick(struct mimimi_chapter_I *chapter)
{
	chapter->foreground.x = -35 * 128;
	chapter->foreground.y = -10 * 128;
	mimimi_background_tick(&chapter->foreground, chapter->engine);
}

static void mimimi_chapter_I_platforms(struct mimimi_chapter_I *chapter)
{
	static unsigned char tiles[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0};
	
	int i;
	void *texture;
	
	for (i = 0 ; i < 1024 ; i++) chapter->platform_colors[i] = 1;
	chapter->platform_image.colors = chapter->platform_colors;
	chapter->platform_image.width = 48;
	chapter->platform_image.height = 16;
	
	texture = (*chapter->engine->texture)(chapter->engine->data, &chapter->platform_image);
	
	for (i = 0 ; i < 4 ; i++)
	{
		mimimi_positioned_physics(&chapter->platforms[i].physics, &chapter->player.sprite.physics, &chapter->player.sprite.position);
		chapter->platforms[i].ground.width = 5;
		chapter->platforms[i].ground.height = 3;
		chapter->platforms[i].ground.tiles = tiles;
		chapter->platforms[i].texture = texture;
	}
	
	chapter->platforms[0].physics.transform.x = -150 * 128;
	chapter->platforms[1].physics.transform.x = -158 * 128;
	chapter->platforms[2].physics.transform.x = -144 * 128;
	chapter->platforms[3].physics.transform.x = -158 * 128;
	
	chapter->momentum.x = 0;
	chapter->momentum.dx = 0;
}

static void mimimi_chapter_I_platforms_propagate(struct mimimi_chapter_I *chapter)
{
	struct mimimi_momentum *momentum;
	struct mimimi_platform *platforms;
	
	momentum = &chapter->momentum;
	platforms = chapter->platforms;
	
	if (platforms[0].physics.other.airborne == 0)
		mimimi_linear_propagate(momentum, platforms[0].physics.transform.y, -14 * 128, 256, 256);
	if (platforms[1].physics.other.airborne == 0)
		mimimi_linear_propagate(momentum, platforms[1].physics.transform.y, -24 * 128, 256, 256);
	if (platforms[2].physics.other.airborne == 0)
		mimimi_linear_propagate(momentum, platforms[2].physics.transform.y, -16 * 128, -256, 256);
	if (platforms[3].physics.other.airborne == 0)
		mimimi_linear_propagate(momentum, platforms[3].physics.transform.y, -26 * 128, -256, 256);
}

static void mimimi_chapter_I_platforms_apply(struct mimimi_chapter_I *chapter)
{
	struct mimimi_momentum *momentum;
	struct mimimi_platform *platforms;
	
	momentum = &chapter->momentum;
	platforms = chapter->platforms;
	
	mimimi_linear_apply(momentum, &platforms[0].physics.transform.y, -14 * 128, 256);
	mimimi_linear_apply(momentum, &platforms[1].physics.transform.y, -24 * 128, 256);
	mimimi_linear_apply(momentum, &platforms[2].physics.transform.y, -16 * 128, -256);
	mimimi_linear_apply(momentum, &platforms[3].physics.transform.y, -26 * 128, -256);
}

static void mimimi_chapter_I_platforms_tick(struct mimimi_chapter_I *chapter)
{
	struct mimimi_momentum *momentum;
	struct mimimi_platform *platforms;
	int i;
	
	momentum = &chapter->momentum;
	platforms = chapter->platforms;
	
	for (i = 0 ; i < 3 ; i++)
		if (platforms[i].physics.other.airborne == 0)
			platforms[i].physics.transform.y += 4;
	
	mimimi_chapter_I_platforms_propagate(chapter);
	
	momentum->dx *= 31;
	momentum->dx /= 32;
	momentum->x += momentum->dx;
	
	if (momentum->x < 0)
	{
		momentum->x = 0;
		momentum->dx = 0;
	}
	if (momentum->x > 1024)
	{
		momentum->x = 1024;
		momentum->dx = 0;
	}
	
	mimimi_chapter_I_platforms_apply(chapter);
	
	for (i = 0 ; i < 4 ; i++)
		mimimi_positioned_physics_tick(&platforms[i].physics, &platforms[i].ground);
}

static void mimimi_chapter_I_platforms_display_tick(struct mimimi_chapter_I *chapter)
{
	int i;
	for (i = 0 ; i < 4 ; i++)
		mimimi_platform_display_tick(chapter->platforms + i, &chapter->clamped_camera.output, -128, -128, chapter->engine);
}

void mimimi_chapter_I_tick(void *data, unsigned char left, unsigned char right)
{
	struct mimimi_chapter_I *chapter;
	
	chapter = data;
	mimimi_offset_tick(&chapter->offset, chapter->origin.x * 128, chapter->origin.y * 128);
	mimimi_history_tick(&chapter->history, left, right);
	mimimi_chapter_I_player_tick(chapter);
	mimimi_chapter_I_platforms_tick(chapter);
	
	mimimi_chapter_I_background_tick(chapter);
	mimimi_chapter_I_platforms_display_tick(chapter);
	mimimi_display_tick(&chapter->player.display, chapter->engine);
	mimimi_chapter_I_foreground_tick(chapter);
	mimimi_camera_tick(&chapter->camera, &chapter->player.sprite.position, 0, -512);
	mimimi_clamped_camera_tick(&chapter->clamped_camera);
	
	if (chapter->progression == 0)
	{
		if (chapter->player.sprite.position.x < -160 * 128 && chapter->player.sprite.position.y <= -50 * 128)
			chapter->progression++;
	}
	if (chapter->progression == 1)
	{
		if (mimimi_toast_dialogue_bottom_tick(&chapter->dialogue) != 0)
			chapter->progression++;
	}
}

void mimimi_chapter_I(void *data, struct mimimi_engine *engine)
{
	struct mimimi_dialogue_paragraph paragraphs[] =
	{
		{0, "Mango", "Hello, world!"},
	};
	
	struct mimimi_dialogue dialogue;
	struct mimimi_chapter_I *chapter;
	
	paragraphs[0].model = mimimi_mango;
	
	chapter = data;
	chapter->engine = engine;
	
	chapter->progression = 0;
	dialogue.count = sizeof paragraphs / sizeof *paragraphs;
	dialogue.paragraphs = paragraphs;
	mimimi_toast_dialogue(&chapter->dialogue, &dialogue, engine);
	
	mimimi_chapter_I_origin(mimimi_chapter_I_ground, &chapter->origin);
	mimimi_chapter_I_sprite(&chapter->player, mimimi_mango, chapter);
	
	chapter->history.left = 0;
	chapter->history.right = 0;
	
	chapter->camera = chapter->player.sprite.position;
	chapter->camera.y -= 512;
	
	mimimi_chapter_I_camera(chapter);
	mimimi_chapter_I_background(chapter);
	mimimi_chapter_I_foreground(chapter);
	
	mimimi_chapter_I_offset(chapter);
	
	mimimi_clamped_camera_tick(&chapter->clamped_camera);
	
	mimimi_chapter_I_platforms(chapter);
}