/** 
 *  _   _        _  _                           _             
 * | |_| |  ___ | || |  ___   __ _  _ __  _ __ (_)  ___  _ __ 
 * |  _  | / _ \| || | / __| / _` || '__|| '__|| | / _ \| '__|
 * | | | ||  __/| || || (__ | (_| || |   | |   | ||  __/| |   
 * |_| |_| \___||_||_| \___| \__,_||_|   |_|   |_| \___||_|   
 * 
 *  (c) 2001 Free Lunch Design, Teknisk-IT, AerotechTelub
 *			  http://www.freelunchdesign.com
 * 
 * This source code is released as is under GPL (General Public
 * License). Please refer to license.txt for more information.
 * 
 */
 
#include <stdio.h>
#include <math.h>
#include "allegro.h"
#include "object.h"
#include "scenery.h"


// constructor
object :: object() {
	selected = FALSE;
	inside = FALSE;
	sect = NULL;
	prev = next = NULL;
}

// destructor
object :: ~object() {
	// TODO: different ~'s depending on object type
}

// sets position of object
void object::set_position(int px, int py) {
	x = px;
	y = py;
}


void object::draw_border(BITMAP *bmp) {
	int hyp = fixtoi(fhypot(itofix(w), itofix(h)))>>1;
	fixed ang = fatan2(itofix(h), itofix(w));
	int cx1 = fixtoi(hyp*fcos(ang+angle));
	int cy1 = fixtoi(hyp*fsin(ang+angle));
	int cx2 = fixtoi(hyp*fcos(-ang+angle+itofix(128)));
	int cy2 = fixtoi(hyp*fsin(-ang+angle+itofix(128)));
	int cx3 = fixtoi(hyp*fcos(ang+angle+itofix(128)));
	int cy3 = fixtoi(hyp*fsin(ang+angle+itofix(128)));
	int cx4 = fixtoi(hyp*fcos(-ang+angle));
	int cy4 = fixtoi(hyp*fsin(-ang+angle));

	line(bmp, render_x - cx1, render_y - cy1, render_x - cx2, render_y - cy2, 1);
	line(bmp, render_x - cx1, render_y - cy1, render_x - cx4, render_y - cy4, 1);
	line(bmp, render_x - cx3, render_y - cy3, render_x - cx2, render_y - cy2, 1);
	line(bmp, render_x - cx3, render_y - cy3, render_x - cx4, render_y - cy4, 1);

	textout_centre(bmp, font, name, render_x, render_y-10, 0);
	textout_centre(bmp, font, name, render_x-1, render_y-11, 1);
}

void object::type_to_string(char *str) {
	switch (type) {
		case OBJ_PROJECTILE:		sprintf(str, "projectile"); return;
		case OBJ_MISSILE:			sprintf(str, "missile"); return;
		case OBJ_SOLDIER:			sprintf(str, "soldier"); return;
		case OBJ_FOOT_SOLDIER:		sprintf(str, "foot_soldier"); return;
		case OBJ_BAZOOKA_SOLDIER:	sprintf(str, "bazooka_soldier"); return;
		case OBJ_JEEP:				sprintf(str, "jeep"); return;
		case OBJ_TRUCK:				sprintf(str, "truck"); return;
		case OBJ_TANK:				sprintf(str, "tank"); return;
		case OBJ_HELI:				sprintf(str, "heli"); return;
		case OBJ_TOWER:				sprintf(str, "tower"); return;
		case OBJ_SCENERY:			sprintf(str, "SCENERY"); return;
		case OBJ_BUILDING:			sprintf(str, "BUILDING"); return;
		default:					sprintf(str, "unknown (%d)", type); return;
	}
}

void object::rotate(double dir) {
	rot_str += dir * rot_step;
}

void object::thrust(double dir) {
	thr_str += dir * thr_step * target_thrust;
}

void object::strafe(double dir) {
	str_str += dir * str_step;
}

void object::calc_movement() {
	angle += ftofix(rot_str);
	double a = fixtof(angle)*2*PI/256;

	x_force = (x_force * f_fric) + thr_str * cos(a + PI/2) + str_str * cos(a);
	y_force = (y_force * f_fric) + thr_str * sin(a + PI/2) + str_str * sin(a);

	rot_str *= rot_fric;
	str_str *= str_fric;
	thr_str *= thr_fric;

	x += x_force;
	y += y_force;
}

void object::reset() {
	rot_str = thr_str = str_str = 
	x_force = y_force = 0;
	target_angle = angle;
}

bool object::collision(int px, int py, double pw, double ph) {
	double dx = x - px;
	double dy = y - py;
	double hyp = sqrt(dx*dx+dy*dy); 

	if (hyp > radius) return FALSE;

	// (c_type == COLL_RECTANGLE) starts here
	double a = atan2(dy, dx) - fixtof(angle)*2*PI/256;
	double nx = x + hyp * cos(a);
	double ny = y + hyp * sin(a);

	if (nx < x-pw*w/2) return FALSE;
	if (nx > x+pw*w/2) return FALSE;
	if (ny < y-ph*h/2) return FALSE;
	if (ny > y+ph*h/2) return FALSE;
	return TRUE;
}

bool object::collision(int px, int py, int r) {
	double dx = x - px;
	double dy = y - py;
	double hyp = sqrt(dx*dx+dy*dy); 

	if (hyp > radius+r) return FALSE;

	double a = atan2(dy, dx) - fixtof(angle)*2*PI/256;
	double nx = x + hyp * cos(a);
	double ny = y + hyp * sin(a);

	if (nx < x-w/2-r) return FALSE;
	if (nx > x+w/2+r) return FALSE;
	if (ny < y-h/2-r) return FALSE;
	if (ny > y+h/2+r) return FALSE;
	return TRUE;
}

bool object::collision(int px, int py, int mx, int my, int c_type) {
	double dx = x - px;
	double dy = y - py;
	double hyp = sqrt(dx*dx+dy*dy); 

	if (hyp > radius) return FALSE;
	else if (c_type == COLL_SPHERE) return TRUE;

	// (c_type == COLL_RECTANGLE) starts here
	double a = atan2(dy, dx) - fixtof(angle)*2*PI/256;
	double nx = x + hyp * cos(a);
	double ny = y + hyp * sin(a);

	if (nx+mx < x-w/2) return FALSE;
	if (nx-mx > x+w/2) return FALSE;
	if (ny+my < y-h/2) return FALSE;
	if (ny-my > y+h/2) return FALSE;
	return TRUE;
}

bool object::collision(object *o, int c_type) {
	double dx = o->x - x;
	double dy = o->y - y;
	double h = sqrt(dx*dx+dy*dy); 
	int my_radius = radius;

	if (c_type == COLL_SEMI_SPHERE) {
		c_type = COLL_SPHERE;
		my_radius /= 3; 
	}

	if (h > my_radius + o->radius) return FALSE;
	else if (c_type == COLL_SPHERE) return TRUE;

	// (c_type == COLL_RECTANGLE) starts here

	my_alert("object::collision", "don't use 'COLL_RECTANGLE' yet!");


	return FALSE;
}

void object::kill() {
	current_mission->obj[index] = NULL;
	sect->remove_object(this);

	if (wreck_image > 0) {
		scenery *s = new scenery();
		s->base_image = wreck_image;
		s->wreck_image = 0;
		s->shadow_image = 0;
		if (type == OBJ_BUILDING || type == OBJ_HELI || type == OBJ_TRUCK || type == OBJ_TANK || type == OBJ_TOWER) s->smoking = 200;
		if (type == OBJ_BUILDING) s->altitude = GL_GROUND_SCENERY;
		s->shadow_dist = shadow_dist>>1;
		s->angle = angle;
		s->set_position(x, y);
		current_mission->add_object(s, TRUE);
		if (s->altitude > GL_GROUND_FLAT_SCENERY) current_mission->space->add_object(s);
	}
}

bool object::is_unit() {
	if (type == OBJ_SOLDIER || type == OBJ_FOOT_SOLDIER || type == OBJ_BAZOOKA_SOLDIER || type == OBJ_JEEP || type == OBJ_TRUCK || type == OBJ_TANK || type == OBJ_HELI || type == OBJ_TOWER) return TRUE;
	return FALSE;
}

bool object::is_armed() {
	if (type == OBJ_FOOT_SOLDIER || type == OBJ_BAZOOKA_SOLDIER || type == OBJ_JEEP || type == OBJ_TANK || type == OBJ_HELI || type == OBJ_TOWER) return TRUE;
	return FALSE;
}


// 'me' wants to know what to shoot at
// type or o->type
bool object::is_more_dangerous_than(object *o, int me) { 
	if (type == OBJ_BUILDING && !o && (me == OBJ_FOOT_SOLDIER || me == OBJ_BAZOOKA_SOLDIER)) return TRUE;
	if (!o) return TRUE;

	if (type == OBJ_FOOT_SOLDIER || type == OBJ_BAZOOKA_SOLDIER) {
		if (o->type == OBJ_BUILDING || o->type == OBJ_TRUCK || o->type == OBJ_SCENERY || o->type == OBJ_SOLDIER) return TRUE;
		return FALSE;
	}
	if (type == OBJ_JEEP) {
		if (o->type == OBJ_TANK || o->type == OBJ_HELI) return FALSE;
		return TRUE;
	}
	if (type == OBJ_TANK || type == OBJ_HELI) return FALSE;
	if (type == OBJ_TOWER) {
		if (o->type == OBJ_TANK || o->type == OBJ_HELI || o->type == OBJ_JEEP) return FALSE;
		return TRUE;
	}

	return FALSE;
}
