Mirai's Miscellaneous Misadventures

M35 / core / sprites.c

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

#include <mimimi/sprites.h>
#include <mimimi/compound-behaviors.h>
#include <mimimi/allocators.h>
#include <mimimi/geometry.h>
#include <mimimi/ground.h>
#include <mimimi/behaviors.h>

struct mimimi_physics_data
{
	struct mimimi_physics *physics;
	struct mimimi_ground *ground;
	struct mimimi_position *position;
};

#include "physics.c"

static void mimimi_physics_behave(void *data)
{
	struct mimimi_physics_data *physics_data = data;
	struct mimimi_physics *physics = physics_data->physics;
	
	if (physics->airborne == 0)
		mimimi_ground_physics(data);
	else
		mimimi_airborne_physics(data);
}

struct mimimi_behavior *mimimi_physics(struct mimimi_physics *physics, struct mimimi_position *position, struct mimimi_ground *ground, struct mimimi_allocator *allocator)
{
	physics->dx = 0;
	physics->dy = 0;
	physics->airborne = 1;
	physics->width = 0;
	physics->height = 0;
	physics->gravity = 3;
	
	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
	struct mimimi_physics_data *data = mimimi_compound_allocate(compound, sizeof *data, allocator);
	mimimi_compound(compound, mimimi_function(data, &mimimi_physics_behave, allocator));
	
	data->physics = physics;
	data->ground = ground;
	data->position = position;
	
	return compound;
}

static void mimimi_live(void *data)
{
	struct mimimi_life *life = data;
	
	if (life->knocked_time != 0)
	{
		life->knocked_time--;
		life->immunity_time = life->recovery_time;
	}
	
	if (life->immunity_time != 0)
	{
		life->pristinity = life->max_pristinity;
		life->immunity_time--;
	}
	
	if (life->pristinity < life->max_pristinity)
		life->pristinity++;
}

struct mimimi_behavior *mimimi_life(struct mimimi_life *life, struct mimimi_allocator *allocator)
{
	life->knocked_time = 0;
	life->immunity_time = 0;
	life->pristinity = 256;
	life->max_pristinity = 256;
	life->recovery_time = 64;
	
	return mimimi_function(life, &mimimi_live, allocator);
}

struct mimimi_fall_data
{
	struct mimimi_fall *fall;
	struct mimimi_physics *physics;
	struct mimimi_life *life;
};

static void mimimi_fall_behave(void *data)
{
	struct mimimi_fall_data *fall_data = data;
	
	if (fall_data->physics->dy > fall_data->fall->max_speed)
	if (fall_data->life->knocked_time < fall_data->fall->knocked_time)
		fall_data->life->knocked_time = fall_data->fall->knocked_time;
}

struct mimimi_behavior *mimimi_fall(struct mimimi_fall *fall, struct mimimi_physics *physics, struct mimimi_life *life, struct mimimi_allocator *allocator)
{
	fall->max_speed = 128;
	fall->knocked_time = 64;
	
	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
	struct mimimi_fall_data *data = mimimi_compound_allocate(compound, sizeof *data, allocator);
	mimimi_compound(compound, mimimi_function(data, &mimimi_fall_behave, allocator));
	
	data->fall = fall;
	data->physics = physics;
	data->life = life;
	
	return compound;
}

struct mimimi_walk_data
{
	struct mimimi_walk *walk;
	struct mimimi_physics *physics;
};

static void mimimi_walk_behave(void *data)
{
	struct mimimi_walk_data *walk_data = data;
	struct mimimi_walk *walk = walk_data->walk;
	struct mimimi_physics *physics = walk_data->physics;
	
	if (walk->direction != 0)
	{
		int ax;
		if (walk_data->physics->airborne)
			ax = walk->airborne_speed;
		else
			ax = walk->ground_speed;
		
		if (walk->direction == 1)
			physics->dx -= ax;
		if (walk->direction == 2)
			physics->dx += ax;
	}
}

struct mimimi_behavior *mimimi_walk(struct mimimi_walk *walk, struct mimimi_physics *physics, struct mimimi_allocator *allocator)
{
	walk->ground_speed = 6;
	walk->airborne_speed = 3;
	walk->direction = 0;
	
	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
	struct mimimi_walk_data *data = mimimi_compound_allocate(compound, sizeof *data, allocator);
	mimimi_compound(compound, mimimi_function(data, &mimimi_walk_behave, allocator));
	
	data->walk = walk;
	data->physics = physics;
	
	return compound;
}

struct mimimi_sprite_data
{
	struct mimimi_behavior *walk_behavior;
	struct mimimi_sprite *sprite;
};

static void mimimi_sprite_behave(void *data0)
{
	struct mimimi_sprite_data *data = data0;
	struct mimimi_sprite *sprite = data->sprite;
	struct mimimi_behavior *walk_behavior = data->walk_behavior;
	
	if (sprite->life->knocked_time == 0)
		sprite->awake = 1,
		(*walk_behavior->behave)(walk_behavior->data);
	else
		sprite->awake = 0;
}

struct mimimi_sprite *mimimi_sprite(struct mimimi_ground *ground, int x, int y, int width, int height, struct mimimi_allocator *allocator)
{
	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
	
	struct mimimi_position *position = mimimi_compound_allocate(compound, sizeof *position, allocator);
	
	struct mimimi_physics *physics = mimimi_compound_allocate(compound, sizeof *physics, allocator);
	struct mimimi_behavior *physics_behavior = mimimi_physics(physics, position, ground, allocator);
	
	struct mimimi_life *life = mimimi_compound_allocate(compound, sizeof *life, allocator);
	struct mimimi_behavior *life_behavior = mimimi_life(life, allocator);
	
	struct mimimi_fall *fall = mimimi_compound_allocate(compound, sizeof *fall, allocator);
	struct mimimi_behavior *fall_behavior = mimimi_fall(fall, physics, life, allocator);
	
	struct mimimi_walk *walk = mimimi_compound_allocate(compound, sizeof *walk, allocator);
	struct mimimi_behavior *walk_behavior = mimimi_walk(walk, physics, allocator);
	mimimi_compound(compound, mimimi_finalizer(walk_behavior->data, walk_behavior->finish, allocator));
	
	struct mimimi_sprite *sprite = mimimi_compound_allocate(compound, sizeof *sprite, allocator);
	struct mimimi_sprite_data *sprite_data = mimimi_compound_allocate(compound, sizeof *sprite_data, allocator);
	sprite->awake = 1;
	
	struct mimimi_behavior *sprite_behavior = mimimi_function(sprite_data, &mimimi_sprite_behave, allocator);
	
	position->x = x;
	position->y = y;
	
	physics->width = width;
	physics->height = height;
	
	sprite_data->walk_behavior = walk_behavior;
	sprite_data->sprite = sprite;
	
	sprite->position = position;
	sprite->physics = physics;
	sprite->life = life;
	sprite->fall = fall;
	sprite->walk = walk;
	sprite->behavior = compound;
	
	mimimi_compound(compound, sprite_behavior);
	mimimi_compound(compound, physics_behavior);
	mimimi_compound(compound, life_behavior);
	mimimi_compound(compound, fall_behavior);
	
	return sprite;
}

struct mimimi_jump_data
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_jump *jump;
	struct mimimi_physics *physics;
};

static void mimimi_jump_behave(void *data)
{
	struct mimimi_jump_data *jump_data = data;
	jump_data->physics->airborne = 1;
	jump_data->physics->dy = -jump_data->jump->strength;
}

static void mimimi_jump_finish(void *data)
{
	struct mimimi_jump_data *jump_data = data;
	mimimi_deallocate(jump_data->allocator, jump_data->behavior);
	mimimi_deallocate(jump_data->allocator, jump_data);
}

struct mimimi_behavior *mimimi_jump(struct mimimi_jump *jump, struct mimimi_physics *physics, struct mimimi_allocator *allocator)
{
	struct mimimi_jump_data *data = mimimi_allocate(allocator, sizeof *data);
	data->allocator = allocator;
	data->jump = jump;
	data->physics = physics;
	
	jump->strength = 56;
	
	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
	data->behavior->behave = &mimimi_jump_behave;
	data->behavior->finish = &mimimi_jump_finish;
	data->behavior->data = data;
	
	return data->behavior;
}

struct mimimi_dash_data
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_dash *dash;
	struct mimimi_physics *physics;
	struct mimimi_walk *walk;
};

static void mimimi_dash_behave(void *data)
{
	struct mimimi_dash_data *dash_data = data;
	if (dash_data->walk->direction == 1)
		dash_data->physics->dx -= dash_data->dash->x_strength;
	if (dash_data->walk->direction == 2)
		dash_data->physics->dx += dash_data->dash->x_strength;
	dash_data->physics->dy -= dash_data->dash->y_strength;
}

static void mimimi_dash_finish(void *data)
{
	struct mimimi_dash_data *dash_data = data;
	mimimi_deallocate(dash_data->allocator, dash_data->behavior);
	mimimi_deallocate(dash_data->allocator, dash_data);
}

struct mimimi_behavior *mimimi_dash(struct mimimi_dash *dash, struct mimimi_physics *physics, struct mimimi_walk *walk, struct mimimi_allocator *allocator)
{
	struct mimimi_dash_data *data = mimimi_allocate(allocator, sizeof *data);
	data->allocator = allocator;
	data->dash = dash;
	data->physics = physics;
	data->walk = walk;
	
	dash->x_strength = 32;
	dash->y_strength = 16;
	
	data->behavior = mimimi_allocate(allocator, sizeof *data->behavior);
	data->behavior->behave = &mimimi_dash_behave;
	data->behavior->finish = &mimimi_dash_finish;
	data->behavior->data = data;
	
	return data->behavior;
}