/** 
 *  _   _        _  _                           _             
 * | |_| |  ___ | || |  ___   __ _  _ __  _ __ (_)  ___  _ __ 
 * |  _  | / _ \| || | / __| / _` || '__|| '__|| | / _ \| '__|
 * | | | ||  __/| || || (__ | (_| || |   | |   | ||  __/| |   
 * |_| |_| \___||_||_| \___| \__,_||_|   |_|   |_| \___||_|   
 * 
 *  (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 "main.h"
#include "dime.h"
#include "vehicle.h"
#include "projectile.h"
#include "soldier.h"
#include "config.h"


// constructor
vehicle :: vehicle(int t) {
	type = t;
	if (type != OBJ_JEEP && type != OBJ_TRUCK && type != OBJ_TANK && type != OBJ_HELI && type != OBJ_TOWER)  {
		//my_alert("vehicle :: vehicle", "unknown vehicle type\ndefaulting to TRUCK");
		type = OBJ_TRUCK;
	}

	reset_wp();

	smoking = 0;
	x = y = w = h = 0;
	exist = TRUE;
	target = FALSE;
	detail_level = DETAIL_LOW;
	angle = 0;
	altitude = (type == OBJ_HELI ? GL_AIR : GL_GROUND_UNIT);
	target_angle = angle;
	ammo_count = 0;
	frame_count = 0;
	wp_dir = 1;
	wp_pos = 0;
	shadow_dist	= (altitude == GL_AIR ? 64 : 8);
	anim_pos = 0;
	anim_count = 0;
	num_passengers = 0;
	may_fire = FALSE;
	target_thrust = 0;
	current_target = NULL;
	angle_counter = 5;
	team = 2;
	event = 0;
	burning = 0;
	essential = FALSE;

	switch(type) {
		case OBJ_JEEP:  set_from_file("data/objects/jeep.txt");  break;
		case OBJ_TRUCK: set_from_file("data/objects/truck.txt"); break;
		case OBJ_TANK:  set_from_file("data/objects/tank.txt");  break;
		case OBJ_HELI:  set_from_file("data/objects/heli.txt");  break;
		case OBJ_TOWER: set_from_file("data/objects/tower.txt"); break;
	}
	max_armour = armour;

	for(int i=0;i<MAX_PASSENGERS;i++)
		passenger[i] = -1;
}



// destructor
vehicle :: ~vehicle() {}

void vehicle::to_string(char *str) {
	sprintf(str, "%s", name);
}

void vehicle::set_turret_stats(DATAFILE *df) {
	if (turret_image) {
		tw = ((BITMAP *)df[turret_image].dat)->w;
		th = ((BITMAP *)df[turret_image].dat)->h;
		tx = w/2-tw/2;
		ty = h/2-th/2;
	}
}

// shows a property dialog
void vehicle::props_dialog(DATAFILE *df) {
	char buf[64];
	if (type == OBJ_JEEP) sprintf(buf, "Vehicle Properties [JEEP]");
	if (type == OBJ_TRUCK) sprintf(buf, "Vehicle Properties [TRUCK]");
	if (type == OBJ_TANK) sprintf(buf, "Vehicle Properties [TANK]");
	if (type == OBJ_HELI) sprintf(buf, "Vehicle Properties [HELI]");
	if (type == OBJ_TOWER) sprintf(buf, "Vehicle Properties [TOWER]");
	dialogf(buf , ALIGN_CENTER, ALIGN_CENTER, 300,
		"Name:%string[32]"
		"Team:%int[0,5]"
		"Active at event: %int[0,31]",
		name, &team, &event);
}

// try to add an object to reside inside this object
// the object should already be added to the mission
bool vehicle::add_object(object *o) {
	if (num_passengers == max_passengers) return FALSE;
	if (o->type != OBJ_SOLDIER && o->type != OBJ_FOOT_SOLDIER && o->type != OBJ_BAZOOKA_SOLDIER && o->type != OBJ_PICKUP) return FALSE;

	// get free slot
	int i=0;
	while(passenger[i] != -1 && i<max_passengers) i++;
	if (i == max_passengers) return FALSE;

	// add object and set some values
	passenger[i] = o->index;
	o->inside = TRUE;
	num_passengers ++;

	return TRUE;
}

// removes the occupants of a vehicle and places outside
void vehicle::empty(mission *m) {
	for(int i=0;i<max_passengers;i++)
		if (passenger[i] != -1) {
			if (m->obj[passenger[i]] != NULL) {
				m->obj[passenger[i]]->inside = FALSE;
				m->obj[passenger[i]]->set_position(x+rand()%radius-radius/2, y+rand()%radius-radius/2);
			}
			//else my_alert("Alert!", "Saved from crash!");

			passenger[i] = -1;
		}

	num_passengers = 0;
}

// removes the occupants of a vehicle and places outside (burning!)
void vehicle::destroy(mission *m) {
	for(int i=0;i<max_passengers;i++)
		if (passenger[i] != -1) {
			if (m->obj[passenger[i]] != NULL) {
				m->obj[passenger[i]]->inside = FALSE;
				m->obj[passenger[i]]->set_position(x+rand()%radius-radius/2, y+rand()%radius-radius/2);
				if ((m->obj[passenger[i]]->type == OBJ_SOLDIER || m->obj[passenger[i]]->type == OBJ_FOOT_SOLDIER || m->obj[passenger[i]]->type == OBJ_BAZOOKA_SOLDIER))
					if (!m->obj[passenger[i]]->essential)
						if (rand()%100>60) {
							((soldier*)m->obj[passenger[i]])->start_fire(60);
							m->obj[passenger[i]]->armour = rand()%15+10;
						}
			}
			//else my_alert("Alert!", "Saved from crash!");

			passenger[i] = -1;
		}

	num_passengers = 0;
}

// removes an occupant of a vehicle and place outside
void vehicle::empty(mission *m, int p) {
	if (passenger[p] != -1) {
		if (m->obj[passenger[p]] != NULL) {
			m->obj[passenger[p]]->inside = FALSE;
			m->obj[passenger[p]]->set_position(x+rand()%20-10, y+rand()%20-10);
		}
		//else my_alert("Alert!", "Saved from crash!");

		passenger[p] = -1;
		num_passengers--;
	}
}

void vehicle::save(PACKFILE *fp) {
	pack_fwrite(name, sizeof(name), fp);
	pack_fwrite(&index, sizeof(index), fp);
	pack_fwrite(&inside, sizeof(inside), fp);
	pack_fwrite(&type, sizeof(type), fp);
	pack_fwrite(&altitude, sizeof(altitude), fp);
	pack_fwrite(&x, sizeof(x), fp);
	pack_fwrite(&y, sizeof(y), fp);
	pack_fwrite(&w, sizeof(w), fp);
	pack_fwrite(&h, sizeof(h), fp);
	pack_fwrite(&exist, sizeof(exist), fp);
	pack_fwrite(&target, sizeof(target), fp);
	pack_fwrite(&detail_level, sizeof(detail_level), fp);
	pack_fwrite(&angle, sizeof(angle), fp);
	pack_fwrite(&base_image, sizeof(base_image), fp);
	pack_fwrite(&shadow_image, sizeof(base_image), fp);
	pack_fwrite(&wreck_image, sizeof(base_image), fp);
	pack_fwrite(&anim_frames, sizeof(anim_frames), fp);
	pack_fwrite(&anim_rate, sizeof(anim_rate), fp);
	pack_fwrite(&armour, sizeof(armour), fp);
	pack_fwrite(file, sizeof(file), fp);
	pack_fwrite(&essential, sizeof(essential), fp);

	pack_fwrite(&event, sizeof(event), fp);
	pack_fwrite(&team, sizeof(team), fp);
	pack_fwrite(&sight_range, sizeof(sight_range), fp);
	pack_fwrite(&sight_angle, sizeof(sight_angle), fp);
	pack_fwrite(&fire_range, sizeof(fire_range), fp);
	pack_fwrite(wp, sizeof(wp), fp);

	pack_fwrite(&max_passengers, sizeof(max_passengers), fp);
	pack_fwrite(&num_passengers, sizeof(num_passengers), fp);
	pack_fwrite(passenger, sizeof(passenger), fp);
	pack_fwrite(&armed, sizeof(armed), fp);
	pack_fwrite(&fire_sound, sizeof(fire_sound), fp);
	pack_fwrite(&reload_sound, sizeof(reload_sound), fp);
	pack_fwrite(&fire_rate, sizeof(fire_rate), fp);
	pack_fwrite(&reload_rate, sizeof(reload_rate), fp);
	pack_fwrite(&turret_turn_speed, sizeof(turret_turn_speed), fp);
	pack_fwrite(&turret_image, sizeof(turret_image), fp);
	pack_fwrite(&tx, sizeof(tx), fp);
	pack_fwrite(&ty, sizeof(ty), fp);
	pack_fwrite(&tw, sizeof(tw), fp);
	pack_fwrite(&th, sizeof(th), fp);
}

void vehicle::load(PACKFILE *fp) {
	pack_fread(name, sizeof(name), fp);
	pack_fread(&index, sizeof(index), fp);
	pack_fread(&inside, sizeof(inside), fp);
	pack_fread(&type, sizeof(type), fp);
	pack_fread(&altitude, sizeof(altitude), fp);
	pack_fread(&x, sizeof(x), fp);
	pack_fread(&y, sizeof(y), fp);
	pack_fread(&w, sizeof(w), fp);
	pack_fread(&h, sizeof(h), fp);
	pack_fread(&exist, sizeof(exist), fp);
	pack_fread(&target, sizeof(target), fp);
	pack_fread(&detail_level, sizeof(detail_level), fp);
	pack_fread(&angle, sizeof(angle), fp);
	pack_fread(&base_image, sizeof(base_image), fp);
	pack_fread(&shadow_image, sizeof(base_image), fp);
	pack_fread(&wreck_image, sizeof(base_image), fp);
	pack_fread(&anim_frames, sizeof(anim_frames), fp);
	pack_fread(&anim_rate, sizeof(anim_rate), fp);
	pack_fread(&armour, sizeof(armour), fp);
	pack_fread(file, sizeof(file), fp);
	pack_fread(&essential, sizeof(essential), fp);

	pack_fread(&event, sizeof(event), fp);
	pack_fread(&team, sizeof(team), fp);
	pack_fread(&sight_range, sizeof(sight_range), fp);
	pack_fread(&sight_angle, sizeof(sight_angle), fp);
	pack_fread(&fire_range, sizeof(fire_range), fp);
	pack_fread(wp, sizeof(wp), fp);

	pack_fread(&max_passengers, sizeof(max_passengers), fp);
	pack_fread(&num_passengers, sizeof(num_passengers), fp);
	pack_fread(passenger, sizeof(passenger), fp);
	pack_fread(&armed, sizeof(armed), fp);
	pack_fread(&fire_sound, sizeof(fire_sound), fp);
	pack_fread(&reload_sound, sizeof(reload_sound), fp);
	pack_fread(&fire_rate, sizeof(fire_rate), fp);
	pack_fread(&reload_rate, sizeof(reload_rate), fp);
	pack_fread(&turret_turn_speed, sizeof(turret_turn_speed), fp);
	pack_fread(&turret_image, sizeof(turret_image), fp);
	pack_fread(&tx, sizeof(tx), fp);
	pack_fread(&ty, sizeof(ty), fp);
	pack_fread(&tw, sizeof(tw), fp);
	pack_fread(&th, sizeof(th), fp);
}

void vehicle::draw(BITMAP *bmp, DATAFILE *gfx, fixed ca, bool shadow) {
	if (type == OBJ_HELI) {
		BITMAP *rotors = (BITMAP *)gfx[turret_image].dat;
		if (downed) return;
		if (heli_altitude == 100) {	// normal
			// shadow
			if (shadow) {
				BITMAP *s = create_bitmap(radius*2, radius*2);
				clear(s);
				rotate_sprite(s, (BITMAP *)gfx[shadow_image].dat, radius-w/2, radius-h/2, angle - ca);
				draw_trans_sprite(bmp, s, render_x+shax*shadow_dist-radius, render_y+shay*shadow_dist-radius);
				destroy_bitmap(s);
			}
			// heli
			rotate_sprite(bmp, (BITMAP *)gfx[base_image].dat, render_x-w/2, render_y-h/2, angle - ca);
			rotate_sprite(bmp, rotors, render_x-rotors->w/2, render_y-rotors->h/2, angle + turret_angle - ca);
		}
		else {		// other altitude
			double scale = (double)heli_altitude/333.3 + 0.6667;
			double sscale = (double)heli_altitude/110.0 + 0.091;
			// shadow
			if (shadow) {
				BITMAP *s = create_bitmap(radius*2, radius*2);
				clear(s);
				rotate_scaled_sprite(s, (BITMAP *)gfx[shadow_image].dat, radius-scale*w/2, radius-scale*h/2, angle - ca, ftofix(scale));
				draw_trans_sprite(bmp, s, render_x+sscale*shax*shadow_dist-radius, render_y+sscale*shay*shadow_dist-radius);
				destroy_bitmap(s);
			}
			// heli
			rotate_scaled_sprite(bmp, (BITMAP *)gfx[base_image].dat, render_x-scale*w/2, render_y-scale*h/2, angle - ca, ftofix(scale));
			rotate_scaled_sprite(bmp, rotors, render_x-scale*rotors->w/2, render_y-scale*rotors->h/2, angle + turret_angle - ca, ftofix(scale));
		}
	}
	else {
		// shadow
		if (shadow) {
			BITMAP *s = create_bitmap(radius*2, radius*2);
			clear(s);
			rotate_sprite(s, (BITMAP *)gfx[shadow_image].dat, radius-w/2, radius-h/2, angle - ca);
			draw_trans_sprite(bmp, s, render_x+shax*shadow_dist-radius, render_y+shay*shadow_dist-radius);
			destroy_bitmap(s);
		}
		// vehicle
		rotate_sprite(bmp, (BITMAP *)gfx[base_image].dat, render_x-w/2, render_y-h/2, angle - ca);

		if(turret_image) rotate_sprite(bmp, (BITMAP *)gfx[turret_image].dat, render_x-w/2+tx, render_y-h/2+ty, turret_angle - ca);
	}

	/*
	for(int i=0;i<max_passengers;i++)
		if (passenger[i]!=-1)
			textprintf(bmp, font, render_x+30*(i+1), render_y, 1, "%d", passenger[i]);

	for(int t=0;t<team;t++)
		circle(bmp, render_x, render_y, radius-t*2, 15);
		*/
//	textprintf(bmp, font, render_x+10, render_y, 1, "%d", index);
	
}



projectile *vehicle::fire(int pt) {
	projectile *p;
	if (pt) {
		p = new projectile(this, pt);
	}
	else {
		if (type == OBJ_TANK || type == OBJ_TOWER) p = new projectile(this, P_N_MISSILE);
		else p = new projectile(this, P_BULLET);
	}

	return p;
}

void vehicle::set_from_file(char *fname) {
	config *c = new config();
	if (c->load_data(fname)) {
		// object stuff
		c->get_data_string("name", name);
		anim_frames = c->get_data_int("anim_frames");
		anim_rate = c->get_data_int("anim_rate");
		base_image = c->get_data_int("base_image");
		shadow_image = c->get_data_int("shadow_image");
		wreck_image = c->get_data_int("wreck_image");
		armour = c->get_data_int("armour");
	
		rot_step = c->get_data_float("rot_step");
		rot_fric = c->get_data_float("rot_fric");
		thr_step = c->get_data_float("thr_step");
		thr_fric = c->get_data_float("thr_fric");
		str_step = c->get_data_float("str_step");
		str_fric = c->get_data_float("str_fric");
		f_fric = c->get_data_float("force_fric");
	
		// unit stuff
		//normal_speed = ftofix(get_config_float(section, "normal_speed", 1.0));
		//panic_speed = ftofix(get_config_float(section, "panic_speed", 2.0));
		max_turn_angle = c->get_data_int("max_turn_angle");
		mag_size = c->get_data_int("mag_size");
		
		fire_range = c->get_data_int("fire_range");
		sight_range = c->get_data_int("sight_range");
		sight_angle = c->get_data_int("sight_angle");
	
		// vehicle stuff
		max_passengers = c->get_data_int("max_passengers");
		armed = c->get_data_int("armed");
		fire_sound = c->get_data_int("fire_sound");
		reload_sound = c->get_data_int("reload_sound");
		fire_rate = c->get_data_int("fire_rate");
		reload_rate = c->get_data_int("reload_rate");
		turret_turn_speed = c->get_data_int("turret_turn_speed");
		turret_image = c->get_data_int("turret_image");
	
	}
	else my_alert("vehicle::set_from_file, file not found", fname);

	
	c->~config();
}

bool vehicle::is_passenger(int oid) {
	if (oid<0) return FALSE;
	for(int i=0;i<max_passengers;i++)
		if (passenger[i] == oid) return TRUE;
	return FALSE;
}


