
#include "BasicEntity.h"

///////////////////////////////////////////////////////////////////////
// example for passing a string to create an entity
long PSTRING(char* chars)
{
// works only for strings no longer than 79 chars!
	static A4_STRING tempstring;
	static char tempname[80];
	strcpy(tempname,chars);
	tempstring.chars = tempname;
	return (long)&tempstring;
}

//  ROTATE_ME rotates the gw entity clockwise (i.e., toward the entities right)
//  by "angle" degrees.  Will handle neg. angles (turn left) as well as
//  angles > 360.  Will NOT show a smooth turn.
void BasicEntity::rotate_me(int turn_angle)  
{
	int temp_pan = FIX2INT(me->pan);
	temp_pan += (turn_angle + 360);
	temp_pan = temp_pan % 360;
	me->pan = INT2FIX(temp_pan);
}

//  ENT_MOVE moves the gw entity from its current position
//  to the position given by x,y,z in ENTITY COORDINATE SYSTEM.
//  Thus, "move(-5,0,0)" will move the entity 5 quants backwards
//  from where the entity is facing, regardless of entity's world
//  coordinates.  Note units are "quants", and that 3DGS's "ent_move"
//  function is used to actually effect the move.  Thus the entity
//  WILL stop on the way to x,y,z IF there is an obstacle (e.g., 
//  map entity, such as a block, a sprite, or another dynamic entity).
//  Also tries to simulate gravity by moving entity down if no floor.
//  directly under it.
//  Updates "current_pos" with actual position after the move.
void BasicEntity::ent_move(int x, int y, int z)
{   
	int temp_dist1[3], temp_dist2[3];
	temp_dist1[0] = INT2FIX(x);
	temp_dist1[1] = INT2FIX(y);
	temp_dist1[2] = INT2FIX(z);
	temp_dist2[0] = INT2FIX(0);
	temp_dist2[1] = INT2FIX(0);
	     
	distance_vector look_down;
	look_down.x = 0;
	look_down.y = 0;
	look_down.z = -1000;
	int distance_down = trace_from_entity(look_down);
	if( distance_down > 30)
		temp_dist2[2] = INT2FIX(-2);
	else if (distance_down > 10)
		temp_dist2[2] = INT2FIX(-1);
	else if (distance_down < 6 &&  distance_down > 3)   
		temp_dist2[2] = INT2FIX(+1);
	else temp_dist2[2] = INT2FIX(0);

	// Need to set the "my" pointer
	(*my_entity_ptr_ptr) = (long) me;

	(*ent_move_fcn_ptr)( (long) temp_dist1, (long) temp_dist2);

	// Update my current position.
	current_pos.x = FIX2INT(me->x);
	current_pos.y = FIX2INT(me->y);
	current_pos.z = FIX2INT(me->z);
}

	  //  TRACE_FROM_ENTITY returns the distance, in quants,
      //  from entity's current_pos to the first obstacle 
	  //  found between current_pos and the x,y,z position "to"
	  //  (assumed to be in ENTITY COORDINATES.  If no obstacle
      //  found between current_pos and "to", then returns 0.
      
int BasicEntity::trace_from_entity(distance_vector to)
{
	distance_vector to_in_world;
	distance_vector my_direction;

	my_direction.x = FIX2INT(me->pan);
	my_direction.y = FIX2INT(me->tilt);
	my_direction.z = FIX2INT(me->roll);

	to_in_world = vec_rotate(to,my_direction);

	to_in_world.x += current_pos.x;
	to_in_world.y += current_pos.y;
	to_in_world.z += current_pos.z;
	return trace(current_pos, to_in_world);
}

void BasicEntity::createMeInWorld(string model_name, int init_position[], string action_name)
{

	for(int i=0; i<3; i++) 
		init_position[i] = INT2FIX(init_position[i]);
	action_ptr = a5dll_getscript( (char *) action_name.c_str() );
		  
	me = (A4_ENTITY*)(*entityCreate_fcn_ptr)( PSTRING((char *) model_name.c_str()), (long) init_position,action_ptr);
	me->skill[24] = (long) this;

}

distance_vector BasicEntity::vec_rotate(distance_vector from, distance_vector to)
{
	int temp_dist1[3], temp_dist2[3];
	temp_dist1[0] = INT2FIX(from.x);
	temp_dist1[1] = INT2FIX(from.y);
	temp_dist1[2] = INT2FIX(from.z);
		     
	temp_dist2[0] = INT2FIX(to.x);
	temp_dist2[1] = INT2FIX(to.y);
	temp_dist2[2] = INT2FIX(to.z);
	
	(*vec_rotate_fcn_ptr)( (long) temp_dist1, (long) temp_dist2 );
	distance_vector rotated_vector; 
	rotated_vector.x = temp_dist1[0];
	rotated_vector.y = temp_dist1[1];
	rotated_vector.z = temp_dist1[2];
	return rotated_vector;
}

int BasicEntity::trace(distance_vector from, distance_vector to)
{
	int temp_dist1[3], temp_dist2[3];
	temp_dist1[0] = INT2FIX(from.x);
	temp_dist1[1] = INT2FIX(from.y);
	temp_dist1[2] = INT2FIX(from.z);
	     
	temp_dist2[0] = INT2FIX(to.x);
	temp_dist2[1] = INT2FIX(to.y);
	temp_dist2[2] = INT2FIX(to.z);

	(*my_entity_ptr_ptr) = (long) me;  // Need to set the "my" pointer

	*trace_mode_ptr = INT2FIX(TRMF_IGNORE_ME + TRMF_IGNORE_PASSABLE + TRMF_USE_BOX);

	return FIX2INT((*trace_fcn_ptr)( (long) temp_dist1, (long) temp_dist2));
}

BasicEntity::BasicEntity() 
{
	my_entity_ptr_ptr = (fixedPoint *) a5dll_getwdlobj("my");
	ent_move_fcn_ptr = (wdlfunc2) a5dll_getwdlfunc("ent_move");
	entityCreate_fcn_ptr = (wdlfunc3) a5dll_getwdlfunc("ent_create");	
	trace_fcn_ptr = (wdlfunc2) a5dll_getwdlfunc("trace");
	trace_mode_ptr = (fixedPoint*)a5dll_getwdlobj("trace_mode");
	action_ptr = (long) a5dll_getwdlobj("CPPaction");
	vec_rotate_fcn_ptr = (wdlfunc2) a5dll_getwdlfunc("vec_rotate");
	vec_to_angle_fcn_ptr = (wdlfunc2) a5dll_getwdlfunc("vec_to_angle");
}

void BasicEntity::create(distance_vector init_locale, string model_file, string action_name)
{
	string model_filename(model_file);
	int initial_pos[3] ={init_locale.x, init_locale.y, init_locale.z};
	createMeInWorld(model_filename,initial_pos,action_name);
}

distance_vector BasicEntity::subtract_vectors(distance_vector v1, distance_vector v2)
{
	distance_vector result;
	result.x = v1.x - v2.x;
	result.y = v1.y - v2.y;
	result.z = v1.z - v2.z;
	return result;
}

int BasicEntity::vector_to_pan(distance_vector direction)
{
	int temp_dist1[3], temp_dist2[3];
	
	temp_dist2[0] = INT2FIX(direction.x);
	temp_dist2[1] = INT2FIX(direction.y);
	temp_dist2[2] = INT2FIX(direction.z);
	
	(*vec_to_angle_fcn_ptr)( (long) temp_dist1, (long) temp_dist2);

	return (FIX2INT(temp_dist1[0]));
}

int BasicEntity::pan_angle_from_v1_to_v2(distance_vector v1, distance_vector v2)
{ 
	return(vector_to_pan(subtract_vectors(v1,v2)));
};

void BasicEntity::rotate_me_to(int new_pan_angle)
{  me->pan = INT2FIX(new_pan_angle%360);}


BasicEntity::~BasicEntity(){}






