/* dragonfly.m,
 *
 * Units that circle around the player.  The path is generated during
 * the game depending on where the player is.
 */

#include <math.h>
#include "common.h"
#include "debris/speed-shadow.h"
#include "player.h"
#include "projectiles/fireball.h"
#include "seborrhea/seborrhea.h"
#include "unit-seeking.h"
#include "units/dragonfly.h"


static SebFile *dragonfly_sebum;


@interface DragonFlyTrail: RotatedSpeedShadow
@end

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

@implementation DragonFly
+ (BOOL) loadPrerequisites { return LOAD_PROJECTILE_DATA_FOR(Fireball); }
+ derive_loadData(dragonfly_sebum, "data/dragonfly");
+ derive_shutdown(dragonfly_sebum);

- init
{
    [super init];

    health = 4;

    sprite = [dragonfly_sebum getSebumByName:"body"];
    shadow = [dragonfly_sebum getSebumByName:"shadow"];
    w = 16;
    h = 16;
    rotatable_unit = YES;

    gun = [[[[DualWeapon new]
		setProjectile:[Fireball class]]
	       setShotDelay:9 WaveDelay:18]
	      setXDisplacement:15 YDisplacement:4];
    
    chunk_colours = CHUNK_GREEN;
    return self;
}

- free
{
    /* The path will be called by Mozzie. */
    if (gun)
	gun = [gun free];
    return [super free];
}

- (BOOL) generatePath
{
#define CP1_SET_XY	[cp1 setX:x Y:y steps:DRAGONFLY_STEPS]
#define CP2_SET_XY	[cp2 setX:x_ Y:y_]

    double x_, y_;
    List *list;
    ControlPoint *cp1, *cp2;

    if (path_segment == 0) {
	target = find_closest_unit(x, y, ALLY_LIST);
	if (!target)
	    return NO;
    }
    else if (!unit_exists(target, ALLY_LIST)) {
	/* Target did exist, but died.  This is rare, so just die. */
	if (the_path) {
	    [self freePathSpline];
	    path_segment = 0;
	}
	[self die];
	return NO;
    }

    [target getX:&x_ Y:&y_];
    list = [LIST_NEW];
    cp1 = [ControlPoint new];
    cp2 = [ControlPoint new];

    if (path_segment == 0) {	  /* Part 1: Above to left of player. */
	x_ -= 75;
	y_ += 25;
	[CP1_SET_XY setControlPoint:1 X:x_-x Y:0];
	[CP2_SET_XY setControlPoint:0 X:0 Y:y-y_];
    }
    else if (path_segment == 1) { /* Part 2: Left to below player. */
	x_ += 75;
	y_ += 25;
	[CP1_SET_XY setControlPoint:1 X:0 Y:y_-y];
	[CP2_SET_XY setControlPoint:0 X:x_-x Y:0];
    }
    else if (path_segment == 2) { /* Part 3: Below to right of player. */
	x_ += 75;
	y_ -= 200;
	[CP1_SET_XY setControlPoint:1 X:x-x_ Y:0];
	[CP2_SET_XY setControlPoint:0 X:0 Y:y-y_];
    }
    else if (path_segment == 3) { /* Part 4: Right to above player. */
	x_ -= 75;
	y_ -= 200;
	[CP1_SET_XY setControlPoint:1 X:0 Y:y_-y];
	[CP2_SET_XY setControlPoint:0 X:x-x_ Y:0];
    }
    else if (path_segment == 4) { /* Part 5: Above to bottom of screen. */
	y_ += screen_h;
	[CP1_SET_XY setControlPoint:1 X:-50 Y:0];
	[CP2_SET_XY setControlPoint:0 X:-50 Y:0];
    }

    {			       /* Common spline articulation stuff. */
	[list insertItem:cp2];
	[list insertItem:cp1];
	if (the_path)
	    the_path = reticulate_spline(the_path, list);
	else
	    the_path = articulate_spline(list);
	[list free];
    }

    return YES;

#undef CP1_SET_XY
#undef CP2_SET_XY
}

- (void) move
{
    if (the_path) {
	[spawn_debris([DragonFlyTrail class], x, y, MEDIUM_LAYER) setAngle:angle];
	x = the_path[path_progress].x;
	y = the_path[path_progress].y;

	path_progress++;
	if (path_progress >= DRAGONFLY_STEPS-10) {
	    path_progress = 0;
	    path_segment++;
	    [self generatePath];
	    flags |= FLAG_FIRING_ENABLED;
	}

	if (unit_exists(target, ALLY_LIST)) {
	    /* Face the target. */
	    double x_, y_;
	    [target getX:&x_ Y:&y_];
	    angle = atan2(y-(y_-10), x_-x);
	}
	else
	    target = nil;
    }
    else
	[super delete];
}

- (void) fire { [gun fireFromX:x Y:y angle:angle]; }
@end

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

@implementation DragonFlyTrail
- init
{
    [super init];
    health = max_health = 10;
    sprite = [dragonfly_sebum getSebumByName:"speedy"];
    return self;
}
@end
