#include "bonus.h"

int nr_bonusses;
bonus *bonusses;
bonus *bonus_recycled;

bonus::bonus(int _type)
{
    x = 0;
    y = 0;
    type = _type;
    score = 0;
    next = 0;
}

bonus::bonus(int _type, int _x, int _y, int _score)
{
    x = _x;
    y = _y;
    type = _type;
    score = _score;
    next = 0;
}

m_rect bonus::get_rect()
{
    m_rect mr;
    
    // dit hangt af van het type van bonus
    switch (type)
    {
	case dead_part:
	    mr.left = x - radius;
	    mr.right = x + radius;
	    mr.top = y - radius;
	    mr.bot = y + radius;
	    break;
	case longer:
	    if (score == 29)
	    {
		mr.left = x - 5 * radius;
		mr.right = x + 5 * radius;
		mr.top = y - 2 * radius;
		mr.bot = y + 2 * radius;
	    }
	    else
	    {
		mr.left = x - 2 * radius;
		mr.right = x + 2 * radius;
		mr.top = y - radius - 2;
		mr.bot = y + radius + 2;
	    }
	    break;
	case chainsaw:
	    mr.left = x - radius;
	    mr.right = x + radius;
	    mr.top = y - radius;
	    mr.bot = y + radius;
	    break;
	case burrow:
	    mr.left = x - radius;
	    mr.right = x + radius;
	    mr.top = y - radius;
	    mr.bot = y + radius;
	    break;
	default:
	    mr.left = x - radius;
	    mr.right = x + radius;
	    mr.top = y - radius;
	    mr.bot = y + radius;
	    break;
    }

    return mr;
}

void bonus::hit(player *p, body *b)
{
    // dit hangt af van het type van bonus
    switch (type)
    {
	case dead_part:
	    // don't crash if we have a chainsaw
	    if (!p->chainsaw_on)
	    {
		p->crash();
		b->crash();
	    }
	    break;
	case longer:
	    b->length += score;
	    p->score += score;
	    p->play(sample_tick);
	    break;
	case chainsaw:
	    p->chainsaw += score;
	    p->burrow = 0;
	    p->play(sample_pling);
	    break;
	case burrow:
	    p->burrow += score;
	    p->chainsaw = 0;
	    p->play(sample_pling);
	    break;
	default:
	    break;
    }
}

void bonus::draw(BITMAP *b)
{
    char buf[10];
    
    // dit hangt af van het type van bonus
    switch (type)
    {
	case dead_part:
	    circlefill(b, x, y, radius, gray);
	    break;
	case longer:
	    if (score == 29)
	    {
		static int colindex = 0;

		colindex++;
		colindex %= 60;
		
		// do some special stuff :)
		rectfill(b, x - 5 * radius, y - 2 * radius,
		     x + 5 * radius, y + 2 * radius, colindex / 3 + 120);
		sprintf(buf, "!!!%d!!!", score);
		textout_centre(b, font, buf, x, y - 4, black);
	    }
	    else
	    {
		rect(b, x - 2 * radius, y - radius - 2,
		     x + 2 * radius, y + radius + 2, gray);
		sprintf(buf, "%d", score);
		textout_centre(b, font, buf, x, y - 4, yellow);
	    }
	    break;
	case chainsaw:
	    circlefill(b, x, y, radius, red);
	    break;
	case burrow:
	    circlefill(b, x, y, radius, green);
	    break;
	default:
	    break;
    }
}

void bonus::clear()
{
    type = dead_part;
    x = 0;
    y = 0;
    score = 0;
    next = 0;
}
    
bonus *new_bonus(int type, int x, int y, int score)
{
    bonus *ret;
    if (bonus_recycled)
    {
	ret = bonus_pop(&bonus_recycled);
	ret->clear();
	ret->type = type;
	ret->x = x;
	ret->y = y;
	ret->score = score;
	ret->next = 0;
    }
    else
	ret = new bonus(type, x, y, score);
    
    return ret;
}

bonus *bonus_remove(bonus **list, bonus *elem)
{
    bonus *tmp = 0;
    bonus *prev = 0;

    tmp = *list;
    if (!tmp)
	return 0;

    if (tmp == elem)
    {
	*list = tmp->next;
	return tmp;
    }
	
    while (tmp)
    {
	prev = tmp;
	tmp = tmp->next;
	
	if (tmp == elem)
	{
	    prev->next = tmp->next;
	    return tmp;
	}
    }

    return 0;
}

bonus *bonus_pop(bonus **list)
{
    bonus *tmp = 0;
    if (*list)
    {
	tmp = *list;
	*list = (*list)->next;
    }

    return tmp;
}

bonus *bonus_pop_list(bonus **list)
{
    bonus *tmp = *list;
    *list = 0;

    return tmp;    
}

void bonus_push(bonus **list, bonus *elem)
{
    if (!elem)
	return;

    elem->next = *list;
    *list = elem;
}

void bonus_push_list(bonus **list, bonus *elem_list)
{
    bonus
	*last;

    if (!elem_list)
	return;

    last = elem_list;
    
    while (last->next)
	last = last->next;

    last->next = *list;
    *list = elem_list;    
}

void init_bonus(int how_many)
{
    nr_bonusses = how_many;
    bonus_recycled = 0;
    bonusses = 0;

    srandom(time(0));
}

void add_bonus(bodypart const &bp)
{
    bonus *tmp = new_bonus(bonus::dead_part, bp.x, bp.y, 0);
    
    bonus_push(&bonusses, tmp);
}

void add_bonus(int type, int x, int y, int score)
{
    bonus *tmp = new_bonus(type, x, y, score);

    bonus_push(&bonusses, tmp);
}

void generate_bonus()
{
    int
	type,
	x,
	y,
	score,
	count = 0;

    // count the number of bonusses, and see if we need to make a new one
    bonus *tmp = bonusses;
    while (tmp)
    {
	if (tmp->type != bonus::dead_part)
	    count++;
	tmp = tmp->next;
    }

    if (count >= nr_bonusses)
	return;
    
    // make a new bonus
    type = 1 + (random() % 3);
    x = 10 + (random() % (MAP_SIZE_X - 20));
    y = 10 + (random() % (MAP_SIZE_X - 20));

    if (type == bonus::longer)
	score = 5 + random() % 25;       // maximum score = 29 :>
    else
	score = 3 + random() % 8;        // chainsaw and burrow 3-10

    add_bonus(type, x, y, score);
}

void draw_bonusses(BITMAP *b)
{
    bonus *tmp = bonusses;
    while (tmp)
    {
	tmp->draw(b);
	tmp = tmp->next;
    }
}

