#include "ScriptUtils.h"

#include <crtdbg.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>


/*
	Misn17Mission
*/

static void GetRidOfSomeScrap(void);

class Misn17Mission {
public:
	Misn17Mission(void);
	~Misn17Mission();

	bool Load(void);
	bool PostLoad(void);
	bool Save(void);

	void Update(void);

	void AddObject(Handle h);
	
private:
	void Setup(void);
	void Execute(void);

struct movePoints { int x,y,z;
};
	
	
	void OffsetCamera(Handle attachObject, Handle targetObject, int xDist, int yDist, int zDist, float speed);
	Vector currentLoc; //move this to the global declarations
	Vector distance; //move this to the global declarations
	Vector turnPerFrame;
	Vector changePerFrame;
	Vector position;
	Vector direction;
	Vector offset;
	movePoints vec;
	void GetDistanceToNextTarget(Vector toPosition);
	void DollyCamera(int heading, float speed);
	bool PanToObject(Handle targetObject, float frames);
	void PanCamera(float speed);
	void FindOffset(Handle targetObject);
	void MoveToChaseCam(Handle targetObject, float speed, int offset, int height, int adjustHeading);
	void ChaseCamera(Handle targetObject, int offset, int height);
	void PlaceCamera(Handle anchorObject, Handle targetObject, int height); 
	//	char takeThisPath[30];

	// bools
	union {
		struct {
			bool
				missionstart, cinDone, beginRotate, endCin, beginZoom, nextThing, 
				theEnd, dontRepeat, b_last;
		};
		bool b_array[8];
	};

	// floats
	union {
		struct {
			float
				r,t, damagecheck1, endCinI, end, cutCounter, offsetMeters,
				f_last;
		};
		float f_array[7];
	};

	// handles
	union {
		struct {
			Handle
				player, animal, cave, buildSite4, buildSite5, ip1, geyser, ip3, ip4, ip5,
				rhino1, rhino2, grass1, grass2, buildSite6, badman1, friend1, startFromHere,
				h_last;
		};
		Handle h_array[18];
	};

	// integers
	union {
		struct {
			int
				newTime, moveTime, moveDistance,
				i_last;
		};
		int i_array[3];
	};
};

bool missionSave;
Misn17Mission *mission;

void Misn17Mission::Setup(void)
{
	/*
		Initialize variables
	*/
	t = 0.0f;
	r = 0.0f;
	offsetMeters = 0.0f;
	rhino1 = 0.0f;
	rhino2 = 0.0f;
	grass1 = 0.0f;
	grass2 = 0.0f;
	end = 0.0f;
  player = 0; 
	animal = 0; 
	cave = 0; 
	buildSite4 = 0; 
	buildSite5 = 0;
	buildSite6 = 0;
	startFromHere = 0;
	badman1 = 0;
	ip1 = 0; 
	geyser = 0;
	ip3 = 0;
	ip4 = 0;
	ip5 = 0;
	friend1 = 0;
	newTime = 0;
	moveTime = 0;
	moveDistance = 0;
	cutCounter = 0.0f;
	beginRotate = false;
	missionstart = false;
	nextThing = false;
	theEnd = false;
	dontRepeat = false;
	
}

Vector AddVectors(const Vector &A, const Vector &B)
{
	Vector v;
	v.x = A.x + B.x;
	v.y = A.y + B.y;
	v.z = A.z + B.z;
	return v;
}

// subtract two vectors
Vector SubVectors(const Vector &A, const Vector &B)
{
	Vector v;
	v.x = A.x - B.x;
	v.y = A.y - B.y;
	v.z = A.z - B.z;
	return v;
}

Vector SetVector(const Vector &A)
{
	Vector v;
	v.x = A.x;
	v.y = A.y;
	v.z = A.z;
	return v;
}

float VecLen(const Vector &A) {
	return (float)sqrt(A.x*A.x + A.y*A.y + A.z*A.z);
}

void Misn17Mission::AddObject(Handle h)
{
}

void addObjective(int count) { 
		
		//PurgeItem("misn1701.otf");
		FILE *fd=fopen("addon\\misn1701.otf","w+");
		fprintf(fd,"You have killed %d enemies.",count);
		fclose(fd);
		ClearObjectives();
		AddObjective("misn1701.otf", WHITE);

}

/* This function replaces CameraObject.  The target object will become the
offset point for any movement specified in the  X Y Z values that are passed
in.  The camera will look at the target object immediatly if the speed is set
to 0.  If speed is set to any other value the camera will interpolate its
direction from where it is now to the target object.
*/

void Misn17Mission::OffsetCamera(Handle attachObject, Handle targetObject, int xDist, int yDist, int zDist, float speed) {
    /* Set the camera position.  The camera will be set at the 
    exact offset specified by the parameters passed to the 
    function.
    */
    Vector rotatePoint = GetPosition(attachObject);
    GetCameraPosition(position, direction);
    position.x = (rotatePoint.x + xDist);
    position.y = (rotatePoint.y + yDist);
    position.z = (rotatePoint.z + zDist);
    
    
    /* Set the direction that the camera is pointing.  If the speed
    is set to 0 the camera will point directly at the object.  If
    the speed is not 0, then the camera will interpolate between its
    current heading and the heading to the target object.    
    */  

    Vector targetPoint = GetPosition(targetObject);
    GetDistanceToNextTarget (targetPoint);
    distance = Normalize_Vector (distance);
    if (speed >= 1) {
		  Vector rotatePerFrame;
      rotatePerFrame.x = ((distance.x - direction.x)/speed);
		  rotatePerFrame.y = ((distance.y - direction.y)/speed);
		  rotatePerFrame.z = ((distance.z - direction.z)/speed);
	    direction.x += rotatePerFrame.x;
		  direction.y += rotatePerFrame.y;
		  direction.z += rotatePerFrame.z;
    }
    else if (speed == 0) {
      direction.x = distance.x;
      direction.y = distance.y;
      direction.z = distance.z;
    }  
    
    SetCameraPosition(position, direction);    
    
}

void Misn17Mission::GetDistanceToNextTarget(Vector toPosition) {
	//	Vector position;
	//	Vector direction;
	//	GetCameraPosition(position, direction);
		distance.x = (toPosition.x - position.x);
		distance.y = (toPosition.y - position.y);
		distance.z = (toPosition.z - position.z);
}

/* DollyCamera will move the camera position in any direction.
The heading (1,2,3) corresponds with the (x,y,z) components of
the position. */

void Misn17Mission::DollyCamera(int heading, float speed) {
		GetCameraPosition(position, direction);
    if (heading == 1) {
      position.x += (direction.x*speed);
    }
    else if (heading == 2) {
      position.y += (direction.y*speed);
    }
    else if (heading == 3) {
      position.z += (direction.z*speed);
    }
		SetCameraPosition(position, direction);
}



/* PanToObject will get the distance to the new target object and
then turn to face the object.  The frames will set the number of frames 
it will take the camera to turn and face the new object */

bool Misn17Mission::PanToObject(Handle targetObject, float frames) {
	bool stopPan = 0;
	GetCameraPosition(position, direction);
	Vector object2 = GetPosition(targetObject);
	GetDistanceToNextTarget(object2);
	distance = Normalize_Vector (distance);
	//Test to see if we are close enough to stop panning
	Vector testVector;
	testVector.x = distance.x - direction.x;
	testVector.y = distance.y - direction.y;
	testVector.z = distance.z - direction.z;
	float test = VecLen(testVector);
	if (test < 0.098) {
		stopPan = 1;
	}
	else if (test >= 0.098) {
		stopPan = 0;
	}
	if (stopPan == 0) {
		direction.x += (distance.x/frames);
		direction.y += (distance.y/frames);
		direction.z += (distance.z/frames);
		SetCameraPosition(position, direction);
	}
	return stopPan;
}

/* This will pan the camera from its current viewing angle. */

void Misn17Mission::PanCamera(float speed) {
	GetCameraPosition(position, direction);
    float rad = ((float) atan2(direction.x,direction.z));

    float temp1 = ((float) sin(rad+speed));
    float temp2 = ((float) cos(rad+speed));
    direction.x = temp1;
    direction.z = temp2;
    SetCameraPosition(position, direction);
	}

void Misn17Mission::FindOffset(Handle targetObject) {
	GetCameraPosition(position, direction);
	Vector object2 = GetPosition(targetObject);
	object2.y = position.y;
	GetDistanceToNextTarget(object2); 
	offsetMeters = VecLen(distance);
 	}

/* This will move the camera into position in a setup for a chase camera.
You could use this function just to get the camera into proximity with a 
vehicle and then go and do something else. */

void Misn17Mission::MoveToChaseCam(Handle targetObject, float speed, int offset, int height, int adjustHeading) {
	//This will set the distance to move the camera
	GetCameraPosition(position, direction);
	Vector object2 = GetPosition(targetObject);
	Vector front = GetFront(targetObject);
    Vector object3;
    object3.x = object2.x + (-front.x*offset);
    object3.y = object2.y + height;
    object3.z = object2.z + (-front.z*offset);
    GetDistanceToNextTarget(object3);
    position.x += (distance.x/speed);
    position.y += (distance.y/speed);
    position.z += (distance.z/speed);
 	
     /*We will do a little interpolation in order to make sure that
       we are pointing at the object.*/
   GetDistanceToNextTarget(object2);
   distance = Normalize_Vector (distance);
	//Update the camera position and direction
 	direction.x = distance.x;
	direction.y = distance.y;
	direction.z = distance.z;
    SetCameraPosition(position, direction);
}

/* The chase camera will attach to the back of the vehicle and follow
it around.  The camera will always point at the vehicle. */

void Misn17Mission::ChaseCamera(Handle targetObject, int offset, int height) {
	//This will set the distance to move the camera
		GetCameraPosition(position, direction);
		Vector object2 = GetPosition(targetObject);
		GetDistanceToNextTarget(object2);
		Vector front = GetFront(targetObject);
		position.x = (object2.x + (-front.x*offset));
		position.y = (object2.y + height);
		position.z = (object2.z + (-front.z*offset));
  		distance = Normalize_Vector (distance);
 		direction.x = distance.x;
		direction.y = distance.y;
		direction.z = distance.z;
		SetCameraPosition(position, direction);

}

void Misn17Mission::PlaceCamera(Handle anchorObject, Handle targetObject, int height) {
	//This will set the distance to move the camera
		Vector object1 = GetPosition(anchorObject);
		object1.y += height;
		position = SetVector(object1);
		//position.x = object1.x;
		//position.y = object1.y;
		//position.z = object1.z;
		Vector object2 = GetPosition(targetObject);
		GetDistanceToNextTarget(object2);
  		distance = Normalize_Vector (distance);
		direction = SetVector(distance);
 		//direction.x = distance.x;
		//direction.y = distance.y;
		//direction.z = distance.z;
		SetCameraPosition(position, direction);
}

void Misn17Mission::Execute(void) {

	if	(missionstart == false) {
		player = GetPlayerHandle ();
		geyser = GetHandle("geyser");
		rhino1 = GetHandle("rhino1");
		rhino2 = GetHandle("rhino2");
		grass1 = GetHandle("grass1");
		grass2 = GetHandle("grass2");
		ip1 = BuildObject("ivrecy", 2, "recyclerSpawn");
		Goto(ip1, geyser);
		endCin = false;
		missionstart = true;
		cutCounter = 1.0f;
		CameraReady();
		ChaseCamera(ip1, 30, 7);
		Vector object = GetFront(player);
		t = ((float) (atan2(object.x,object.z)));
		end = (t + 3.141f);
 	}
	
	if ((cutCounter == 1.0f) && (t <= end)) { //circle around player vehicle
		OffsetCamera(player, player, (int)(sin(t)*50), 7, (int)(cos(t)*50), 0.0f);
		t += 0.09f;  
  } 
	else if ((cutCounter == 1.0f) && (t > end)) {
		r = 0.0f;
		t = 0.0f;
		end = 0.0f;
		cutCounter = 1.1f;
		SetCameraPosition(position, direction);
  }
	else if ((cutCounter == 1.1f) && (r <= 10)) { //pan to recycler
		bool stopPan = PanToObject(ip1, 8);
		if (stopPan = 1) {
			r = 11;
		}
		r += 1.0f;
	}
	else if ((cutCounter == 1.1f) && (r > 10)) {
		r = 0.0f;
		cutCounter = 2.0f;	
		SetCameraPosition(position, direction);
		ip4 = BuildObject("ivtank", 1, "recyclerSpawn");
		ip5 = BuildObject("ivtank", 1, "recyclerSpawn");
		Attack(ip4, ip1);
		Attack(ip5, ip1);
	}
	else if ((cutCounter == 2.0f) && (r <= 50.0f)) { //follow the recycler
		MoveToChaseCam(ip1, 10, 40, 7, 1);
		r += 1.0f;
	}
	else if ((cutCounter == 2.0f) && (r > 50.0f)) {
		r = 0.0f;
		cutCounter = 3.0f;
		Vector object = GetFront(ip1);
		t = (atan2(object.x,object.z) - 3.141);
		end = (t + 5.5f);
		FindOffset(ip1);
		SetCameraPosition(position, direction);
	}
	
	else if ((cutCounter == 3.0f) && (t <= end)) { //circle the moving recycler
		OffsetCamera(ip1, ip1, (sin(t))*offsetMeters, 7, (cos(t))*offsetMeters, 0.0f);
		t += 0.07f;
	}
	else if ((cutCounter == 3.0f) && (t > end)) {
		r = 0.0f;
		cutCounter = 4.0f;
		ip3 = BuildObject("ivtank", 1, "goto1");
		Attack(ip3, ip1);
		//Goto(ip3, "path_in", 1);
		SetCameraPosition(position, direction);
	}
	else if ((cutCounter == 4.0f) && (r <= 20)) { //pan to spawned tank
		bool panTest = PanToObject(ip3, 15);
		if (panTest = 1) {
			r = 21;
		}

		r += 1.0f;
	}
	else if ((cutCounter == 4.0f) && (r > 20)) {
		cutCounter = 5.0f;
		t = 0.0f;
		r = 0.0f;
		end = 0.0;
		SetCameraPosition(position, direction);
	}
	else if ((cutCounter == 5.0f) && (r <= 25.0f)) { //follow spawned tank
 		MoveToChaseCam(ip3, 8, 40, 7, 1);
 		r += 1.0f;
 	}
	else if ((cutCounter == 5.0f) && (r > 25.0f)) {
		r = 0.0f;
		cutCounter = 6.0f;
		FindOffset(ip3);
		SetCameraPosition(position, direction);
	}
	else if ((cutCounter == 6.0f) && (IsAlive(ip1))) { //pan back to recycler
		PanToObject(ip3, 10);
		if (r == 15) {
			Damage(ip1, 20000);
		}
		r++;
	}
	else if ((cutCounter == 6.0f) && (!IsAlive(ip1))) {
		r = 0.0f;
		cutCounter = 7;
		SetCameraPosition(position, direction);
		Goto(ip3, "path_in");
	}
	else if ((cutCounter == 7.0f) && (r < 50)) { //pan back to recycler
		PanToObject(ip3, 10);
		r++;
	}
	else if ((cutCounter == 7.0f) && (r >= 50)) {
		r = 0.0f;
		cutCounter = 8;
		SetCameraPosition(position, direction);
		RemoveObject(ip3);
		ip1 = BuildObject("mogrss01", 2, "cameraAnimal");
		ip3 = BuildObject("ivtank", 1, grass1);
		Attack(ip3, rhino1);
	}

	else if ((cutCounter == 8.0f) && (IsAlive(rhino1))) { //pan with the tank as it goes under bridge
		if (r == 0){
			PlaceCamera(ip1, rhino1, 10);
		}
		else if (r > 0) {
			PanToObject(ip3, 30);
		}
		r++;
	}
	else if ((cutCounter == 8.0f) && (!IsAlive(rhino1))) {
		RemoveObject(ip1);
		CameraFinish();
		r = 0.0f;
		cutCounter = 9;

	}
// -- end

}



Misn17Mission::Misn17Mission(void)
{
}

Misn17Mission::~Misn17Mission()
{
}

bool Misn17Mission::Load(void)
{
	if (missionSave) {
		int i;

		// init bools
		int b_count = &b_last - b_array;
		_ASSERTE(b_count == SIZEOF(b_array));
		for (i = 0; i < b_count; i++)
			b_array[i] = false;

		// init floats
		int f_count = &f_last - f_array;
		_ASSERTE(f_count == SIZEOF(f_array));
		for (i = 0; i < f_count; i++)
			f_array[i] = 99999.0f;

		// init handles
		int h_count = &h_last - h_array;
		_ASSERTE(h_count == SIZEOF(h_array));
		for (i = 0; i < h_count; i++)
			h_array[i] = 0;

		// init ints
		int i_count = &i_last - i_array;
		_ASSERTE(i_count == SIZEOF(i_array));
		for (i = 0; i < i_count; i++)
			i_array[i] = 0;

		Setup();
		return true;
	}

	bool ret = true;

	// bools
	int b_count = &b_last - b_array;
	_ASSERTE(b_count == SIZEOF(b_array));
	ret = ret && in(b_array, sizeof(b_array));

	// floats
	int f_count = &f_last - f_array;
	_ASSERTE(f_count == SIZEOF(f_array));
	ret = ret && in(f_array, sizeof(f_array));

	// Handles
	int h_count = &h_last - h_array;
	_ASSERTE(h_count == SIZEOF(h_array));
	ret = ret && in(h_array, sizeof(h_array));

	// ints
	int i_count = &i_last - i_array;
	_ASSERTE(i_count == SIZEOF(i_array));
	ret = ret && in(i_array, sizeof(i_array));

	return ret;
}

bool Misn17Mission::PostLoad(void)
{
	if (missionSave)
		return true;

	bool ret = true;

	int h_count = &h_last - h_array;
	for (int i = 0; i < h_count; i++)
		h_array[i] = ConvertHandle(h_array[i]);

	return ret;
}

bool Misn17Mission::Save(void)
{
	if (missionSave)
		return true;

	bool ret = true;

	// bools
	int b_count = &b_last - b_array;
	_ASSERTE(b_count == SIZEOF(b_array));
	ret = ret && out(b_array, sizeof(b_array), "b_array");

	// floats
	int f_count = &f_last - f_array;
	_ASSERTE(f_count == SIZEOF(f_array));
	ret = ret && out(f_array, sizeof(f_array), "f_array");

	// Handles
	int h_count = &h_last - h_array;
	_ASSERTE(h_count == SIZEOF(h_array));
	ret = ret && out(h_array, sizeof(h_array), "h_array");

	// ints
	int i_count = &i_last - i_array;
	_ASSERTE(i_count == SIZEOF(i_array));
	ret = ret && out(i_array, sizeof(i_array), "i_array");

	return ret;
}

void Misn17Mission::Update(void)
{
	Execute();
}

bool Save(bool misnSave)
{
	missionSave = misnSave;
	return mission->Save();
}

bool Load(bool misnSave)
{
	mission = new Misn17Mission();
	missionSave = misnSave;
	return mission->Load();
}

bool PostLoad(bool misnSave)
{
	missionSave = misnSave;
	return mission->PostLoad();
}

void AddObject(Handle h)
{
	mission->AddObject(h);
}

void Update(void)
{
	mission->Update();
}

void PostRun(void)
{
	delete mission;
}

static MisnExport misnExport;
MisnImport misnImport;

MisnExport * __cdecl GetMisnAPI(MisnImport *import)
{
	misnImport = *import;
	misnExport.misnImport = &misnImport;
	misnExport.Save = Save;
	misnExport.Load = Load;
	misnExport.PostLoad = PostLoad;
	misnExport.AddObject = AddObject;
	misnExport.Update = Update;
	misnExport.PostRun = PostRun;
	return &misnExport;
}

