
#include <sstream>

#include "gameobject.h"
#include "commonplayer.h"


void ModuloScreen(Vector2* v)
{
	// Hier werden *Differenzen* normalisiert, nicht Positionen !!!
	while (v->x < -0.5 * ScreenSize.x) v->x += ScreenSize.x; 
	while (v->x >  0.5 * ScreenSize.x) v->x -= ScreenSize.x;
	while (v->y < -0.5 * ScreenSize.y) v->y += ScreenSize.y;
	while (v->y >  0.5 * ScreenSize.y) v->y -= ScreenSize.y;
}	

void ModuloScreen(Vector2* v, GameObject* enemy, Ship* ship)
{
	// t gibt die Stärke an, wie bald das Schiff dem Objekt entgegenschießt
	// wenn es von ihm wegfliegt, anstatt ihm hinterherzufeuern
	// FUNKTIONIERT MOMENTAN MÖGLICHERWEISE, vielleicht auch nicht
	// notwendig, das mal genau durchzurechnen. Wert t = 100 sinnvolle 
	// Größenordnung
	
	int t = 0;

	*v = enemy->pos - ship->pos;
				
	// Hier werden *Differenzen* normalisiert, nicht Positionen !!!
	while (v->x < -0.5 * ScreenSize.x + enemy->vel.x * t) v->x += ScreenSize.x; 
	while (v->x >  0.5 * ScreenSize.x - enemy->vel.x * t) v->x -= ScreenSize.x;
	while (v->y < -0.5 * ScreenSize.y + enemy->vel.y * t) v->y += ScreenSize.y; 
	while (v->y >  0.5 * ScreenSize.y - enemy->vel.y * t) v->y -= ScreenSize.y;
}	

GameObject::GameObject() {
	
	this->radius = 0;
	this->prio = 0;
	this->points = 0;
	this->sf = 0;
	this->snipered = 0;
	this->flagUpdate = false;
	this->m_updates = 0;
	this->objecttype = 0;
	this->age = 0; 
	this->tag = 0;
	this->att_flighttime = 0;
	this->att_alpha = 0;
	
	avg_index = SPEED_AVERAGING - 1; // Kleiner Fake damit 1. Geschwindigkeitswert wegfällt
	m_updates = 0;
	// wichtig wegen AutoIntegrationScheme
	//vx = 0;
	//vy = 0; // vel ist automatisch (0/0)
	//m_arrayIndex = -1;
	//snipered = false;
}
/*
const char* GameObject::GetObjectName() {
	return "Error: GameObject::GetObjectName";
}

float GameObject::Matches(GameObject* o, int delta_dist) {
	if (GetObjectName() != o->GetObjectName())
		return 0;

  	if (std::strcmp(GetObjectName(), "Asteroid") == 0) {
  	//if (objecttype == TYPE_ASTEROID)
		return ((Asteroid*) this)->Matches((Asteroid*) o, delta_dist);
	} else {
		DistanceState ds;
		CalculateDistance(ds, *this, *o);
		if (ds.dist <= delta_dist)
			return 1;
	}

	return 0;
}
*/

// Falls frames verloren gehen kann das Objekt auf Basis
// der vorher ermittelten Geschwindigekeit automagisch 
// weiterbewegt werden 
void GameObject::AutoIntegrationScheme(int frames) {
	/*
	ox = x;
	oy = y;
	x = ox + (int) (vx * frames);
	if (x < SCREEN_MIN_X)	// -1 -> 1023 
		x = x + SCREEN_MAX_X + 1;
	if (x > SCREEN_MAX_X)	// 1024 -> 0
		x = x % (SCREEN_MAX_X + 1);
		
	y = oy + (int) (vy * frames);
	if (y < SCREEN_MIN_Y)	// 127 -> 895
		y = SCREEN_MAX_Y - SCREEN_MIN_Y - y;
	if (y > SCREEN_MAX_X)	// 896 -> 128
		y = y - SCREEN_MAX_Y + SCREEN_MIN_Y;		
		
	m_updates++;
	*/
}

// nur für debugging
Vector2* GameObject::getAvg(int i)
{
	return &(this->avg[i]);	
}

void GameObject::PositionalUpdate(int x_new, int y_new)
{
	temp.set(x_new, y_new);
}

void GameObject::PositionalUpdate(GameObject* g)
{
	temp = g->temp;
}

void GameObject::IntegrationScheme(int lostframes)
{
	// Kompensation für verlorene Frames NICHT IMPLEMENTIERT!!!
	
	Vector2 diff_pos, old_vel = vel;
	
	if (temp.length2() == 0) temp = pos; 
	
	// Gegen den vel-Sprung am Bildschirmrand
	diff_pos = temp - pos;
	ModuloScreen(&diff_pos);
	//if (diff_pos.length() > 2 * SHOT_VELOCITY) diff_pos.clear();
		
	// Behandlung für neue Asteroiden 	
	int runTo = SPEED_AVERAGING;
	if (age < SPEED_AVERAGING) runTo = age - 1;
			
	// Speed averaging
	avg[avg_index++] = diff_pos; // / (lostframes + 1);
	if (avg_index >= SPEED_AVERAGING) avg_index = 0;
		
	if (runTo > 0)
	{
		vel.clear();
		for (int i = 0; i < runTo; i++)
			vel += avg[i];
		vel /= runTo;
	}
		
	pos = temp;
	force = vel - old_vel; // Masse m = 1
	
	// Alter des Objekts
	age++;
		
	m_updates++;	
}
/*
const char* GameObject::ToString() {
	std::stringstream str;
	str << "x: " << x << " - y: " << y;
	return str.str().c_str();
}
*/

void GameObject::toFuture(int frames)
{
	pos += vel * frames;
}

char* GameObject::putToString()
{
	// Sche*ss Funktion soll einfach nen String zurückgeben. Kann denn sowas so schwer sein
	// in C++ ??? Momentan würde der Speicher vollaufen...
	char *prtstr = new char[80];
	sprintf(prtstr, "Typ: %d, x(%.0f, %.0f), t(%.0f, %.0f), v(%.2f, %.2f), rad: %d, prio: %d\n", objecttype, pos.x, pos.y, temp.x, temp.y, vel.x, vel.y, radius, prio);		
	return prtstr;
}


Asteroid::Asteroid() 
{
	objecttype = TYPE_ASTEROID; 
	sf = -1;
	tag = rand();
}
	
Asteroid::Asteroid(int x, int y, int type, int scaleFactor) 
{
	this->pos.set(x, y);
	this->type = type;
	this->sf = scaleFactor;
	this->objecttype = TYPE_ASTEROID;
	tag = rand();
	
	this->set(x, y, type, scaleFactor);
}

void Asteroid::set(int _x, int _y, int _type, int _sf)
{	
	PositionalUpdate(_x, _y);

	type = _type;
	sf = _sf;

	if (_sf == 0)
	{
	  points = 20;		// groß
	  radius = RADIUS_BIG;
	}
	else if (_sf == 15)
	{
	  points = 50;		// mittel
	  radius = RADIUS_MEDIUM;
	}
	else
	{
	  points = 100;	  // klein
	  radius = RADIUS_SMALL;
	}
}

Saucer::Saucer()
{
	objecttype = TYPE_SAUCER;
	sf = -1;	
}

Saucer::Saucer(int x, int y, int size) 
{
	this->pos.set(x, y);
	this->objecttype = TYPE_SAUCER;
	this->sf = -1;	
	this->size = size;
	
	this->set(x, y, size);
}

bool Saucer::IsPresent (void) const
{
	return size > 0;	
}

void Saucer::set(int _x, int _y, int _size)
{
	PositionalUpdate(_x, _y);
  	
	size = _size;

	if (_size == 15)
	{
		points = 200;	  // groß
		radius = RADIUS_MEDIUM;
	}
	else
	{
		points = 1000;	 // klein
		radius = RADIUS_SMALL;
	}
}

Explosion::Explosion()
{
	objecttype = TYPE_EXPLOSION;
	sf = -1;	
}

Explosion::Explosion(int x, int y, int size, int scaleFactor) {
	//this->x = x;
	//this->y = y;
	this->pos.set(x, y);
	this->objecttype = TYPE_EXPLOSION;
	this->sf = -1;	
	this->size = size;
	this->sf = scaleFactor;
	
	this->set(x, y, size, scaleFactor);	
}

void Explosion::set(int _x, int _y, int _size, int _sf)
{
	PositionalUpdate(_x, _y);
  
  	size = _size;
  	sf = _sf;
}

Ship::Ship()
{
	this->objecttype = TYPE_SHIP;
	this->sf = -1;	
	this->Winkelbyte = 0;
}

bool Ship::IsPresent (void) const
{
	return present;
}

void Ship::ChangeWinkelbyte(int k)
{
	if (abs(k) > 0) 
	{
		Winkelbyte += k;
	}
	else
		Winkelbyte = 0;
		
	while (Winkelbyte <   0) Winkelbyte += 256;
	while (Winkelbyte > 255) Winkelbyte -= 256;
	
}

float Ship::winkel(int i)
{
	float f = (i / (float) 256) * 6 * Pi;
	while(f > Pi) f -= 2*Pi;
	return f;
}

float Ship::omega()
{
	return winkel(Winkelbyte);	 
}	
		
int Ship::calibrateWinkelbyteByView(int rotations)
{
	int index;
	float p = this->view.phase();
	vector<int>* currRow;
	
	if (p < 0) p += 2*Pi;
		
	index = (int) round(this->view.phase() * VIEWSTEP_COUNT / (2*Pi));
	if (index < 0) index += VIEWSTEP_COUNT;
		
	currRow = wbyte[index];
		
	int d, w, best_wink = -1, min = 1000;
	for (int i = 0; i < currRow->size(); i++)
	{
		// Suche dem aktuellen WB ähnlichstes WB in der zum View passenden
		// Zeile der Tabelle
		// Die Rotation des letzten Frames mit einrechnen bei Entscheidung!!!
		w = currRow->at(i) + rotations;
		d = abs(Winkelbyte - w);
		if (d < min) 
		{
			min = d;
			best_wink = w;
		}
	}
	
	return best_wink;
}

void Ship::set(int _x, int _y, int _viewx, int _viewy)
{
	PositionalUpdate(_x, _y);
	view.set(_viewx, _viewy);
	
	present = true;
	radius = RADIUS_SHIP;
}

Shot::Shot()
{
	objecttype = TYPE_SHOT;
	sf = -1;
}

Shot::Shot(int x, int y)
{
	this->pos.set(x, y);
	this->objecttype = TYPE_SHOT;
	
	this->set(x, y);
}

void Shot::set(int _x, int _y)
{
	PositionalUpdate(_x, _y);
}


// Winkelbytes=========================

vector<int>* assign(int v0, int v1, int v2, int v3, int v4, int v5, int v6, int v7)
{
	int *temp = new int[8];
	vector<int> *a = new vector<int>; 
		
	temp[0] = v0;
	temp[1] = v1;
	temp[2] = v2;
	temp[3] = v3;
	temp[4] = v4;
	temp[5] = v5;
	temp[6] = v6;
	temp[7] = v7;
	
	for (int i = 0; i < temp[0]; i++)
		a->push_back(temp[i+1]);
	
	return a;
} 

void initialize_winkelbyte()
{
	wbyte[0] = assign(7, 0, 1, 85, 86, 170, 171, 255);
	wbyte[1] = assign(4, 2, 87, 172, 173, -1, -1, -1);
	wbyte[2] = assign(4, 3, 88, 89, 174, -1, -1, -1);
	wbyte[3] = assign(4, 4, 5, 90, 175, -1, -1, -1);
	wbyte[4] = assign(4, 6, 91, 176, 177, -1, -1, -1);
	wbyte[5] = assign(4, 7, 92, 93, 178, -1, -1, -1);
	wbyte[6] = assign(4, 8, 9, 94, 179, -1, -1, -1);
	wbyte[7] = assign(4, 10, 95, 180, 181, -1, -1, -1);
	wbyte[8] = assign(4, 11, 96, 97, 182, -1, -1, -1);
	wbyte[9] = assign(4, 12, 13, 98, 183, -1, -1, -1);
	wbyte[10] = assign(4, 14, 99, 184, 185, -1, -1, -1);
	wbyte[11] = assign(4, 15, 100, 101, 186, -1, -1, -1);
	wbyte[12] = assign(4, 16, 17, 102, 187, -1, -1, -1);
	wbyte[13] = assign(4, 18, 103, 188, 189, -1, -1, -1);
	wbyte[14] = assign(4, 19, 104, 105, 190, -1, -1, -1);
	wbyte[15] = assign(4, 20, 21, 106, 191, -1, -1, -1);
	wbyte[16] = assign(1, 192, -1, -1, -1, -1, -1, -1);
	wbyte[17] = assign(4, 22, 107, 108, 193, -1, -1, -1);
	wbyte[18] = assign(4, 23, 24, 109, 194, -1, -1, -1);
	wbyte[19] = assign(4, 25, 110, 195, 196, -1, -1, -1);
	wbyte[20] = assign(4, 26, 111, 112, 197, -1, -1, -1);
	wbyte[21] = assign(4, 27, 28, 113, 198, -1, -1, -1);
	wbyte[22] = assign(4, 29, 114, 199, 200, -1, -1, -1);
	wbyte[23] = assign(4, 30, 115, 116, 201, -1, -1, -1);
	wbyte[24] = assign(4, 31, 32, 117, 202, -1, -1, -1);
	wbyte[25] = assign(4, 33, 118, 203, 204, -1, -1, -1);
	wbyte[26] = assign(4, 34, 119, 120, 205, -1, -1, -1);
	wbyte[27] = assign(4, 35, 36, 121, 206, -1, -1, -1);
	wbyte[28] = assign(4, 37, 122, 207, 208, -1, -1, -1);
	wbyte[29] = assign(4, 38, 123, 124, 209, -1, -1, -1);
	wbyte[30] = assign(4, 39, 40, 125, 210, -1, -1, -1);
	wbyte[31] = assign(4, 41, 126, 211, 212, -1, -1, -1);
	wbyte[32] = assign(7, 42, 43, 127, 128, 129, 213, 214);
	wbyte[33] = assign(4, 44, 45, 130, 215, -1, -1, -1);
	wbyte[34] = assign(4, 46, 131, 216, 217, -1, -1, -1);
	wbyte[35] = assign(4, 47, 132, 133, 218, -1, -1, -1);
	wbyte[36] = assign(4, 48, 49, 134, 219, -1, -1, -1);
	wbyte[37] = assign(4, 50, 135, 220, 221, -1, -1, -1);
	wbyte[38] = assign(4, 51, 136, 137, 222, -1, -1, -1);
	wbyte[39] = assign(4, 52, 53, 138, 223, -1, -1, -1);
	wbyte[40] = assign(4, 54, 139, 224, 225, -1, -1, -1);
	wbyte[41] = assign(4, 55, 140, 141, 226, -1, -1, -1);
	wbyte[42] = assign(4, 56, 57, 142, 227, -1, -1, -1);
	wbyte[43] = assign(4, 58, 143, 228, 229, -1, -1, -1);
	wbyte[44] = assign(4, 59, 144, 145, 230, -1, -1, -1);
	wbyte[45] = assign(4, 60, 61, 146, 231, -1, -1, -1);
	wbyte[46] = assign(4, 62, 147, 232, 233, -1, -1, -1);
	wbyte[47] = assign(4, 63, 148, 149, 234, -1, -1, -1);
	wbyte[48] = assign(1, 64, -1, -1, -1, -1, -1, -1);
	wbyte[49] = assign(4, 65, 150, 235, 236, -1, -1, -1);
	wbyte[50] = assign(4, 66, 151, 152, 237, -1, -1, -1);
	wbyte[51] = assign(4, 67, 68, 153, 238, -1, -1, -1);
	wbyte[52] = assign(4, 69, 154, 239, 240, -1, -1, -1);
	wbyte[53] = assign(4, 70, 155, 156, 241, -1, -1, -1);
	wbyte[54] = assign(4, 71, 72, 157, 242, -1, -1, -1);
	wbyte[55] = assign(4, 73, 158, 243, 244, -1, -1, -1);
	wbyte[56] = assign(4, 74, 159, 160, 245, -1, -1, -1);
	wbyte[57] = assign(4, 75, 76, 161, 246, -1, -1, -1);
	wbyte[58] = assign(4, 77, 162, 247, 248, -1, -1, -1);
	wbyte[59] = assign(4, 78, 163, 164, 249, -1, -1, -1);
	wbyte[60] = assign(4, 79, 80, 165, 250, -1, -1, -1);
	wbyte[61] = assign(4, 81, 166, 251, 252, -1, -1, -1);
	wbyte[62] = assign(4, 82, 167, 168, 253, -1, -1, -1);
	wbyte[63] = assign(4, 83, 84, 169, 254, -1, -1, -1);

}









