Mirai's Miscellaneous Misadventures

M23 / core / controls.c

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

#include <mimimi/controls.h>
#include <mimimi/behaviors.h>
#include <mimimi/allocators.h>
#include <mimimi/sprites.h>
#include <mimimi/chapters.h>

struct mimimi_history_data
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_history *history;
	struct mimimi_chapter *chapter;
};

static void mimimi_history_behave(void *data0)
{
	struct mimimi_history_data *data = data0;
	data->history->left <<= 1;
	data->history->left |= data->chapter->left;
	data->history->right <<= 1;
	data->history->right |= data->chapter->right;
}

static void mimimi_history_finish(void *data)
{
	struct mimimi_history_data *history_data = data;
	(*history_data->allocator->deallocate)(history_data->behavior);
	(*history_data->allocator->deallocate)(history_data);
}

struct mimimi_behavior *mimimi_history(struct mimimi_history *history, struct mimimi_chapter *chapter, struct mimimi_allocator *allocator)
{
	struct mimimi_history_data *data = (*allocator->allocate)(sizeof *data);
	data->allocator = allocator;
	data->history = history;
	data->chapter = chapter;
	
	history->left = 0;
	history->right = 0;
	
	data->behavior = (*allocator->allocate)(sizeof *data->behavior);
	data->behavior->behave = &mimimi_history_behave;
	data->behavior->finish = &mimimi_history_finish;
	data->behavior->data = data;
	
	return data->behavior;
}

struct mimimi_controls_data
{
	struct mimimi_allocator *allocator;
	struct mimimi_behavior *behavior;
	struct mimimi_controls *controls;
	struct mimimi_walk *walk;
	struct mimimi_history *history;
};

static unsigned char mimimi_count_oscillations(unsigned int history)
{
	unsigned char count = 0;
	unsigned char prev = history&1;
	for (int i = 0 ; i < 16 ; i++)
	{
		if ((history&1) != prev) count++;
		prev = history&1;
		history >>= 1;
	}
	return count;
}

static void mimimi_control(void *data)
{
	struct mimimi_controls_data *controls_data = data;
	
	struct mimimi_walk *walk = controls_data->walk;
	struct mimimi_history *history = controls_data->history;
	
	struct mimimi_behavior *jump = controls_data->controls->jump;
	
	unsigned char left_oscillations = mimimi_count_oscillations(history->left);
	unsigned char right_oscillations = mimimi_count_oscillations(history->right);
	
	switch (walk->direction)
	{
	case 0:
		if ((history->left&1) != 0)
			walk->direction = 1;
		if ((history->right&1) != 0)
			walk->direction = 2;
		break;
	case 1:
		if ((history->left&1) == 0)
			walk->direction = 0;
		else if (left_oscillations > 1)
			(*jump->behave)(jump->data);
		
		if ((history->right&1) != 0)
		{
			if (right_oscillations == 0)
			{
				// rapid attack
			}
		}
		if ((history->right&1) != 0 && (history->right&2) == 0)
		{
			// attack
		}
		break;
	case 2:
		if ((history->right&1) == 0)
			walk->direction = 0;
		else if (right_oscillations > 1)
			(*jump->behave)(jump->data);
		
		if ((history->left&1) != 0)
		{
			if (left_oscillations == 0)
			{
				// rapid attack
			}
		}
		if ((history->left&1) != 0 && (history->left&2) == 0)
		{
			// attack
		}
		break;
	}
}

static void mimimi_controls_finish(void *data)
{
	struct mimimi_controls_data *controls_data = data;
	(*controls_data->allocator->deallocate)(controls_data->behavior);
	(*controls_data->allocator->deallocate)(controls_data);
}

struct mimimi_behavior *mimimi_controls(struct mimimi_controls *controls, struct mimimi_walk *walk, struct mimimi_history *history, struct mimimi_allocator *allocator)
{
	struct mimimi_controls_data *data = (*allocator->allocate)(sizeof *data);
	data->allocator = allocator;
	data->controls = controls;
	data->walk = walk;
	data->history = history;
	
	controls->jump = mimimi_noop;
	
	data->behavior = (*allocator->allocate)(sizeof *data->behavior);
	data->behavior->behave = &mimimi_control;
	data->behavior->finish = &mimimi_controls_finish;
	data->behavior->data = data;
	
	return data->behavior;
}

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;
	if (jump_data->physics->airborne == 0)
	{
		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;
	(*jump_data->allocator->deallocate)(jump_data->behavior);
	(*jump_data->allocator->deallocate)(jump_data);
}

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