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

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


static SebFile *mozzie_sebum;


@interface MozzieTrail: RotatedSpeedShadow
@end

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

@implementation Mozzie
+ (BOOL) loadPrerequisites { return LOAD_PROJECTILE_DATA_FOR(Fireball); }
+ derive_loadData(mozzie_sebum, "data/mozzie");
+ derive_shutdown(mozzie_sebum);

- init
{
    [super init];

    health = 2;
    the_path = NULL;
    path_progress = 0;
    /* Note: speed has no effect. */

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

    projectile = [Fireball class];
    shot_delay = 10;

    chunk_colours = CHUNK_GREEN;
    return self;
}

- (void) freePathSpline { FREE_SPLINE(the_path); }

- free
{
    [self freePathSpline];
    return [super free];
}

- (BOOL) generatePath
{
    double x_, y_, x1, x2, x3, y1, y2, y3;

    target = find_closest_unit(x, y, ALLY_LIST);
    if (!target)
	return NO;

    [target getX:&x_ Y:&y_];

    x1=x;
    y1=y;
    x2=x_ + ((x_ > x) ? 80 : -80);
    y2=y_-40;
    x3=((x_ > x) ? -50 : screen_w+50);;
    y3=y_+60;

    {				/* Make the spline. */
	List *list = [LIST_NEW];
	ControlPoint *cp1 = [ControlPoint new];
	ControlPoint *cp2 = [ControlPoint new];
	ControlPoint *cp3 = [ControlPoint new];

	[[cp1 setX:x Y:y steps:MOZZIE_STEPS/2]
	    setControlPoint:1  X:(x2-x1)/2 Y:(y2-y1)/4];
	[[[cp2 setX:x2 Y:y2 steps:MOZZIE_STEPS/2]
	     setControlPoint:0 X:(x1-x3)/10 Y:(y1-y3)/10]
	    setControlPoint:1  X:(x3-x1)/10 Y:(y3-y1)/10];
	[[cp3 setX:x3 Y:y3]
	    setControlPoint:0  X:(x2-x3)*0.95 Y:0];

	[list insertItem:cp3];
	[list insertItem:cp2];
	[list insertItem:cp1];

	the_path = articulate_spline(list);

	[list free];
    }

    /* Displacements. */
    path_x_displacement = x;
    path_y_displacement = y;
    return YES;
}

- (BOOL) readyToActivate
{
    if ([super readyToActivate])
	return [self generatePath];

    return NO;
}

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

	path_progress++;
	if (path_progress >= MOZZIE_STEPS) {
	    [self freePathSpline];
	}
	else if (path_progress > 90)
	    flags &=~FLAG_FIRING_ENABLED;
	else if (path_progress > 10)
	    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_, x_-x);
	}
	else
	    target = nil;
    }
    else
	[super delete];
}

- (void) fire
{
    if (!projectile || --fire_tics > 0)
	return;

    [spawn_projectile(projectile, x, y, NO) setAngle:angle];
    fire_tics = shot_delay;
}

- derive_fixedAngle;
@end

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

@implementation MozzieHatch
+ (BOOL) loadPrerequisites { return LOAD_UNIT_DATA_FOR(Mozzie, YES); }

- (id) init
{
    [super init];
    spawnee = [Mozzie class];
    return self;
}

- (void) spawnUnit
{
#define SPAWN_MOZZIE(x,y)	(Mozzie *)spawn_unit(spawnee, x, y, ACTIVE_AIR_LIST, YES)

    /* Spawn 3(!) Mozzies (and into ACTIVE_AIR_LIST, not ground). */
    [SPAWN_MOZZIE(x,    y-13) generatePath];
    [SPAWN_MOZZIE(x-13, y+13) generatePath];
    [SPAWN_MOZZIE(x+13, y+13) generatePath];
    spawnee = nil;

#undef SPAWN_MOZZIE
}

- (void) draw:(BITMAP *)dest
{
    [super draw:dest];

    /* Fade 3 Mozzies into existance. */
    if (spawnee && anim.frame > 0) {
	double x_, y_;
	Sebum<SebImage> *hatchee = [mozzie_sebum getSebumByName:"hatchme"];
	if (not hatchee)
	    return;

	x_ = x - offsetX - [hatchee width]/2;
	y_ = y - offsetY - [hatchee height]/2;

	[hatchee drawTo:dest X:x_    Y:y_-13 Alpha:alpha];
	[hatchee drawTo:dest X:x_-13 Y:y_+13 Alpha:alpha];
	[hatchee drawTo:dest X:x_+13 Y:y_+13 Alpha:alpha];
    }
}
@end

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

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