summaryrefslogblamecommitdiff
path: root/saedit/animation.c
blob: 997b420fce674fa9fd2e563ac58d1dd24b45ae8f (plain) (tree)

































































































































































































































































































































































































                                                                              
#include "animation.h"
#include <string.h>

static void
animation_add_element_pause (
	Animation *animation,
	gint delay,
	gint rand,
	gint line_no
) {
	AnimElement *elem = animation_element_new ();
	elem->delay  = delay;
	elem->rand   = rand;
	elem->type   = ELEMENT_PAUSE;
	elem->line_no = line_no;

	animation->elements = g_list_append (animation->elements, elem);
}

static void
animation_add_element_end (
	Animation *animation,
	gint rand,
	gint line_no
) {
	AnimElement *elem = animation_element_new ();
	elem->type    = ELEMENT_END;
	elem->rand    = rand;
	elem->line_no = line_no;

	animation->elements = g_list_append (animation->elements, elem);
}

static void
animation_add_element_frame (
	Animation *animation,
	const Imageset *imageset,
	gint index,
	gint offsetX,
	gint offsetY,
	gint delay,
	gint rand,
	gint line_no
) {
	gint x, y;
	AnimElement *elem = animation_element_new ();

	elem->type    = ELEMENT_FRAME;

	imageset_get_offset (imageset, &x, &y);
	offsetX += x;
	offsetY += y;

	imageset_get_size (imageset, &x, &y);
	offsetX -= x / 2;
	offsetY -= y;

	elem->offsetX = offsetX;
	elem->offsetY = offsetY;
	
	elem->delay   = delay;
	elem->rand    = rand;
	elem->line_no = line_no;

	elem->sprite = imageset_get_sprite_by_index (imageset, index);
	if (elem->sprite == NULL) {
		/* TODO: report this */
		g_free (elem);
		return;
	}

	animation->elements = g_list_append (animation->elements, elem);
}

static void
animation_add_element_goto (
	Animation *animation,
	gchar *label,
	gint   rand,
	gint   line_no
) {
	AnimElement *elem = animation_element_new ();
	elem->type = ELEMENT_GOTO;
	elem->str  = label;
	elem->rand = rand;
	elem->line_no = line_no;

	animation->elements = g_list_append (animation->elements, elem);
}

static void
animation_add_element_jump (
	Animation *animation,
	gchar *action,
	gint   rand,
	gint   line_no
) {
	AnimElement *elem = animation_element_new ();
	elem->type = ELEMENT_JUMP;
	elem->str  = action;
	elem->rand = rand;
	elem->line_no = line_no;

	animation->elements = g_list_append (animation->elements, elem);
}

static void
animation_add_element_label (
	Animation *animation,
	gchar *name,
	gint line_no
) {
	AnimElement *elem = animation_element_new ();
	elem->type = ELEMENT_LABEL;
	elem->str  = name;
	elem->line_no = line_no;

	animation->elements = g_list_append (animation->elements, elem);
}

static void
animation_add_sequence (
	Animation     *animation,
	const Imageset *imageset,
	const XMLNode *node,
	gint           offsetX,
	gint           offsetY,
	gint           delay,
	gint           rand,
	gint           line_no
) {
	gchar *value, **tokens;
	gint start  = xml_node_get_int_attr_value (node, "start", -1);
	gint end    = xml_node_get_int_attr_value (node,   "end", -1);
	gint repeat = xml_node_get_int_attr_value_limited (
		node, "repeat", 1, 0, 100
	);

	g_return_if_fail (g_strcmp0 (node->name, "sequence") == 0);

	if (repeat < 1) {
		/* TODO: show error */
		return;
	}

	value = xml_node_get_attr_value (node, "value");

	if (value == NULL) {
		if (start < 0 || end < 0) {
			/* TODO: show error */
			return;
		}
		value = g_strdup_printf ("%d-%d", start, end);
	}

	tokens = g_strsplit (value, ",", 0);
	g_free (value);

	while (repeat > 0) {
		gchar **token = tokens;

		while (*token != NULL) {
			if (g_strcmp0 (*token, "p") == 0) {
				animation_add_element_pause (
					animation,
					delay,
					rand,
					line_no
				);
			} else {
				gint start = -1, end = -1, d;
				gchar *delim = strchr (*token, '-');

				if (delim == NULL) {
					try_strtoint (*token, &start);
					end = start;
				} else {
					*delim = 0;
					try_strtoint (   *token, &start);
					try_strtoint (delim + 1,   &end);
					*delim = '-';
				}

				if (start < 0 || end < 0) {
					/* TODO: show error */
					g_strfreev (tokens);
					return;
				}

				d = start <= end ? +1 : -1;
				end += d;

				while (start != end) {
					animation_add_element_frame (
						animation,
						imageset,
						start,
						offsetX,
						offsetY,
						delay,
						rand,
						line_no
					);
					start += d;
				}
			}
			++token;
		}
		--repeat;
	}

	g_strfreev (tokens);
}

static void
animation_add_elements_from_node (
	Animation *animation,
	const Imageset *imageset,
	const XMLNode *node,
	gint  included_from
) {
	gchar *name = node->name;

	gint   offsetX, offsetY;
	gint   delay, rand;
	gchar *str;
	gint   line_no;

	imageset_get_offset (imageset, &offsetX, &offsetY);

	offsetX += xml_node_get_int_attr_value (node, "offsetX", 0);
	offsetY += xml_node_get_int_attr_value (node, "offsetY", 0);

	delay = xml_node_get_int_attr_value_limited (
		node, "delay", 0, 
		0, 100000
	);

	rand = xml_node_get_int_attr_value_limited (
		node, "rand", 100,
		0, 100
	);

	line_no = included_from;
	if (line_no == -1)
		line_no = node->line_no;

	if (g_strcmp0 (name, "frame") == 0) {
		gint index = xml_node_get_int_attr_value (node, "index", -1);
		
		if (index < 0) {
			/* TODO: report error */
			return;
		}

		animation_add_element_frame (
			animation,
			imageset,
			index,
			offsetX, offsetY,
			delay, rand,
			line_no
		);
	} else

	if (g_strcmp0 (name, "pause") == 0) {
		animation_add_element_pause (
			animation, delay, rand, line_no
		);
	} else

	if (g_strcmp0 (name, "end") == 0) {
		animation_add_element_end (animation, rand, line_no);
	} else

	if (g_strcmp0 (name, "jump") == 0) {
		str = xml_node_get_attr_value (node, "action");
		animation_add_element_jump (
			animation, str, rand, line_no
		);
	} else

	if (g_strcmp0 (name, "label") == 0) {
		str = xml_node_get_attr_value (node, "name");
		if (str == NULL) {
			/* TODO: report error */
			return;
		}

		animation_add_element_label (animation, str, line_no);
	} else
	
	if (g_strcmp0 (name, "goto") == 0) {
		str = xml_node_get_attr_value (node, "label");
		if (str == NULL) {
			/* TODO: report error */
			return;
		}

		animation_add_element_goto (
			animation, str, rand, line_no
		);
	} else

	if (g_strcmp0 (name, "sequence") == 0) {
		animation_add_sequence (
			animation, 
			imageset,
			node,
			offsetX, offsetY,
			delay, rand,
			line_no
		);
	} else

	{
		/* TODO: unknown tag */
		return;
	}
}

Animation *
animation_new (
	const Imageset *imageset,
	const XMLNode *node,
	gint included_from
) {
	Animation *animation;
	gchar     *dir;
	GList     *sub_node;

	g_return_val_if_fail (g_strcmp0 (node->name, "animation") == 0, NULL);
	
	dir = xml_node_get_attr_value (node, "direction");

	if (dir == NULL)
		dir = "";

	animation = (Animation *) g_new0 (Animation, 1);
	animation->direction = dir;

	sub_node = node->sub_nodes;
	while (sub_node != NULL) {
		animation_add_elements_from_node (
			animation,
			imageset,
			(XMLNode *) sub_node->data,
			included_from
		);
		sub_node = g_list_next (sub_node);
	}

	return animation;
}

gint
animation_compare_by_direction (
	const Animation *first,
	const Animation *second
) {
	return g_strcmp0 (first->direction, second->direction);
}

gboolean
animation_direction_equals (
	const Animation *animation,
	const gchar *direction
) {
	return g_strcmp0 (animation->direction, direction) == 0;
}

void
animation_free (Animation *animation) {
	g_list_free_full (
		animation->elements,
		(GDestroyNotify) g_free
	);

	g_free (animation->direction);
	g_free (animation);
}

AnimElement *
animation_element_new () {
	return (AnimElement *) g_new0 (AnimElement, 1);
}