/* debri.m,
 *
 * Stuff that doesn't contribute to gameplay outside of eye-candy.  It
 * is used for chunks, explosions, smoke, sparks, etc.
 */

#include <allegro.h>
#include <assert.h>
#include <math.h>
#include "common.h"
#include "debri.h"
#include "linklist.h"
#include "seborrhea/container-animation.h"
#include "seborrhea/seborrhea.h"


#define ASSERT_LAYER(x)		assert(x < TOTAL_LAYERS)
#define foreach_layer(x)	for (x = SUBTERRANIAN_LAYER; x < TOTAL_LAYERS; x++)


int debri_amount = 2;


static List *debris_list[TOTAL_LAYERS];


@implementation Debri
        /* Initialization. */
- init
{
    [super init];

    sprite = (Sebum<SebImage> *)[base_sebum getSebumByName:"dummy8x8"];
    w = [sprite width];
    h = [sprite height];
    recalculate_velocity = YES;

    return self;
}

- (id) setAngle:(double)theta;
{
    angle = theta;
    recalculate_velocity = YES;
    return self;
}

	/* Update. */
- (int) update
{
    /* The angle was changed, recalculate xv/yv. */
    if (recalculate_velocity) {
	xv = speed * cos(angle);
	yv = speed * sin(angle);
	recalculate_velocity = NO;
    }

    x += xv;
    y -= yv;

    return [super update];
}
@end

@implementation AnimatedDebriNoLoop: Debri
- (int) update
{
    if (sprite && [(SebAnimator *)sprite animationEnded])
	return THING_DEAD;
    return [super update];
}
@end

/*------------------------------------------------------------*/

void draw_debris(BITMAP *dest, enum DEBRI_LAYER layer)
{
    ListIterator *it;

    ASSERT_LAYER(layer);

    foreach (it, debris_list[layer])
	[[it getItem] draw:dest];
}


void update_debris(void)
{
    ListIterator *it, *nx;
    enum DEBRI_LAYER l;

    foreach_layer (l) {
	foreach_nx (it, nx, debris_list[l]) {
	    Debri *debris = [it getItem];
	    nx = [it next];

	    if ([debris update] == THING_DEAD) {
                [debris_list[l] removeItem:debris];
                [debris free];
            }
	}
    }
}


Debri *spawn_debris(Class class, int x, int y, enum DEBRI_LAYER layer)
{
    Debri *debris;
    ASSERT_LAYER(layer);

    debris = [class new];
    if (not debris)
	return nil;

    [debris setX:x Y:y];
    [debris_list[layer] insertItem:debris];
    return debris;
}

/*-----------------------------------------------------------*/

void debris_init(void)
{
    enum DEBRI_LAYER l;

    foreach_layer (l) {
        debris_list[l] = [LIST_NEW];
	assert(debris_list[l]);
    }
}


void debris_shutdown(void)
{
    enum DEBRI_LAYER l;

    foreach_layer (l) {
        if (debris_list[l])
            debris_list[l] = [debris_list[l] free];
    }
}
