/*
 * $Id: legoman.cpp,v 1.26 2002/07/22 12:07:36 msell Exp $
 *
 *
 * $Log: legoman.cpp,v $
 * Revision 1.26  2002/07/22 12:07:36  msell
 * Pää kiinni
 *
 * Revision 1.25  2002/07/22 01:14:14  msell
 * Lopetussysteemi
 *
 * Revision 1.24  2002/07/21 22:50:39  msell
 * no message
 *
 * Revision 1.23  2002/07/21 20:14:28  msell
 * no message
 *
 * Revision 1.22  2002/07/21 16:37:00  msell
 * no message
 *
 * Revision 1.21  2002/07/21 15:12:16  msell
 * Äänet enabloitu :)
 *
 * Revision 1.20  2002/07/21 15:03:12  msell
 * Äänet disabloitu
 *
 * Revision 1.19  2002/07/19 18:59:46  msell
 * Alkuhommaa ja säätöä
 *
 * Revision 1.18  2002/07/18 23:05:31  msell
 * Partikkelit ja kakkospelaajan liike
 *
 * Revision 1.17  2002/07/17 22:45:54  msell
 * Ääniä vähän
 *
 * Revision 1.16  2002/07/16 19:52:09  jkaarlas
 * kämmenet hienosäädetty
 *
 * Revision 1.15  2002/07/16 07:27:32  jkaarlas
 * nyt latautuu kämmen. paikka ja väri pitää vielä säätää
 *
 * Revision 1.14  2002/07/16 00:42:43  msell
 * Uusia skyboxeja ja areenan säätöä
 *
 * Revision 1.13  2002/07/15 22:03:23  msell
 * MultiAppearance
 *
 * Revision 1.12  2002/07/15 15:22:08  msell
 * Parantelua
 *
 * Revision 1.11  2002/07/14 21:40:43  msell
 * Conflictit pois, liikkumiset (hyppy, kävely, lyönti), uusi areena
 *
 * Revision 1.10  2002/07/14 21:22:39  jkaarlas
 * skybox ja ukkojen säätö
 *
 * Revision 1.9  2002/07/11 18:33:58  jkaarlas
 * mallit paikoillaan, vaatii säätöä
 *
 * Revision 1.8  2002/07/10 22:22:53  msell
 * Cartoon-rendaus
 *
 * Revision 1.7  2002/07/10 21:17:02  msell
 * Ukon geometrian viilausta
 *
 * Revision 1.6  2002/07/10 17:13:44  msell
 * Törmäystarkastelun parantelua
 *
 * Revision 1.5  2002/07/08 22:53:38  msell
 * Säätöä
 *
 * Revision 1.4  2002/07/08 18:28:47  msell
 * Törmäystä ja ukkoja
 *
 * Revision 1.3  2002/07/07 23:21:11  msell
 * Pientä parantelua
 *
 * Revision 1.2  2002/07/07 23:05:22  msell
 * Osien liimaaminen toisiinsa (kesken)
 *
 * Revision 1.1  2002/07/07 17:53:21  msell
 * Legoukon alku
 *
 *
 *
 * $Date: 2002/07/22 12:07:36 $
 *
 */

#include "main.h"

#include <math.h>

#include "legoman.h"
#include "object.h"
#include "sphere.h"
#include "world.h"
#include "legoblocks.h"
#include "vector.h"
#include "collision.h"
#include "objectfactory.h"
#include "utils.h"
#include "particle.h"
#include "fight.h"
#include "glapi.h"




BodyPart::BodyPart(Legoman *parent, float strength){
	this->parent = parent;
	this->strength = strength;
	reset();
}

void BodyPart::reset(void){
	this->energy = 1;
	this->attached = true;
	this->immortal = 0;
	vectorSet(position, 0, 0, 0);
	vectorSet(momentum, 0, 0, 0);
	matrixIdentity(rotation);
	vectorSet(angularmomentum, 0, 0, 0);
}

void BodyPart::move(void){
	if (immortal > 0) immortal--;
	Object::move();
}

void BodyPart::hitForce(float speed, float *speed2, Object *source){
	if (parent->isHarmfulObject(source)){
		float tolerance = 0.3;
		if (speed > tolerance){
			Sound *sound;
			sound = hitsound1;
			float volume = (speed-tolerance)*0.4;
			if (volume > 1) volume = 1;
			volume = 1;
			sound->setVolume(volume);
			sound->play(30 + random(120));

			int i;
			for (i = 0; i < (int)(speed-0.5); i++){
				float vel[3] = {randomf(2)-1, randomf(3), randomf(2)-1};
				vectorAdd(vel, speed2);
				createBlood(position, vel);
			}

			//makeDamage(0.1);
			if (this == parent->head && source == parent->opponent->head){
				speed *= 0.1;
			}
			makeDamage(speed*0.1);
		}
	} else{
		Object::hitForce(speed, speed2, source);
	}
}

void BodyPart::makeDamage(float amount){
	if (strength == 0) return;
	if (energy == 0) return;
	if (!parent->opponent->isAlive()) return;
	if (immortal > 0) return;

	energy -= amount/strength;
	if (energy < 0) energy = 0;
	if (energy == 0){
		parent->releasePart(this);
	}
	immortal = 30;
}


Sensor::Sensor(){
}

void Sensor::attach(Object *object, float *relativeposition){
	vectorCopy(this->relativeposition, relativeposition);
	this->object = object;
	update();
	update();
	update();
	update();
}

void Sensor::attach(Object *object){
	float position[3] = {0, 0, 0};
	attach(object, position);
}

void Sensor::update(void){
	vectorCopy(oldposition, position);
	vectorCopy(oldvelocity, velocity);

	object->transformPoint(position, relativeposition);

	vectorSub(velocity, position, oldposition);
	vectorSub(acceleration, velocity, oldvelocity);

	//printf("V: %f, %f, %f\n", velocity[0], velocity[1], velocity[2]);
}

void Sensor::getPosition(float *target){
	vectorCopy(target, position);
}

void Sensor::getVelocity(float *target){
	vectorCopy(target, velocity);
}

void Sensor::getAcceleration(float *target){
	vectorCopy(target, acceleration);
}

//float rightHandOffset[3] = {-0.60, 0.45, 0.0};
float rightHandOffset[3] = {-0.40, 0.45, 0.0};
//float leftHandOffset[3] = {0.60, 0.46, 0.0};
float leftHandOffset[3] = {0.40, 0.46, 0.0};
//float leftPalmOffset[3] = {0.28, -0.3, -0.38};
float leftPalmOffset[3] = {0.08, -0.3, -0.38};
//float rightPalmOffset[3] = {-0.30, -0.3, -0.38};
float rightPalmOffset[3] = {-0.10, -0.3, -0.38};
float waistOffset[3] = {0.0, 0.2, 0.0};
float rightLegOffset[3] = {-0.15, 0.4, 0.0};
float leftLegOffset[3] = {0.1, 0.4, 0.0};

Legoman::Legoman(int side){
	this->side = side;

	int collisiongroup, collisiongrouphand;
	if (side == PLAYER1){
		collisiongroup = COLLISIONGROUP_MAN1;
		collisiongrouphand = COLLISIONGROUP_MAN1HAND;
	}
	if (side == PLAYER2){
		collisiongroup = COLLISIONGROUP_MAN2;
		collisiongrouphand = COLLISIONGROUP_MAN2HAND;
	}

	float torsocolor[3], legcolor[3];

	if (side == PLAYER1){
		vectorSet(torsocolor, 1, 0, 0);
		vectorSet(legcolor, 0, 0, 1);
	} else if (side == PLAYER2){
		vectorSet(torsocolor, 0, 0, 1);
		vectorSet(legcolor, 1, 0, 0);
	}	

	//Legs
  Mesh* geomLegMesh = createBox(-0.45, 0.45, -BLOCKHEIGHT*LEGHEIGHT/2.0, BLOCKHEIGHT*LEGHEIGHT/2.0, -0.5, 0.5);
	float tmpScale = 1.0;    
	
	//Left leg
	{
		leftleg = new BodyPart(this, 8);
    Mesh* leftLegMesh = loadAscModel((char*)LEFTLEGASC, MODELSCALE, leftLegOffset);
		MeshShape *leftLegGeom = new MeshShape(leftleg, geomLegMesh);
		leftleg->geometry = leftLegGeom;
		leftleg->appearance = new MeshAppearance(leftLegMesh);
		//leftleg->appearance = new MeshAppearance(geomLegMesh);
		leftleg->appearance->material.setColor(legcolor[0], legcolor[1], legcolor[2], 1);
		vectorSet(leftleg->position, -0.6, BLOCKHEIGHT*(LEGHEIGHT/2.0), 0);
		leftleg->setGravity(true);
		leftleg->setMass(LEGHEIGHT/3.0);
		leftleg->setCollisionGroup(collisiongroup);
	}

	//Right leg
	{
		rightleg = new BodyPart(this, 8);
    Mesh* rightLegMesh = loadAscModel((char*)RIGHTLEGASC, MODELSCALE, rightLegOffset);
		MeshShape *rightLegGeom = new MeshShape(rightleg, geomLegMesh);
		rightleg->geometry = rightLegGeom;
		rightleg->appearance = new MeshAppearance(rightLegMesh);
		//rightleg->appearance = new MeshAppearance(geomLegMesh);
		rightleg->appearance->material.setColor(legcolor[0], legcolor[1], legcolor[2], 1);
		vectorSet(rightleg->position, 0.6, BLOCKHEIGHT*(LEGHEIGHT/2.0), 0);
		rightleg->setGravity(true);
		rightleg->setMass(LEGHEIGHT/3.0);
		rightleg->setCollisionGroup(collisiongroup);
	}
	
	
	//Waist
	{
		waist = new BodyPart(this, 0);
    Mesh* waistMesh = loadAscModel((char*)WAISTASC, MODELSCALE, waistOffset);
    MeshAppearance* waistappearance = new MeshAppearance(waistMesh);
		waistappearance->material.setColor(0, 1, 0, 1);

		Mesh *waistGeomMesh = createBox(-1 + 0.1, 1 - 0.1, 0, BLOCKHEIGHT*WAISTHEIGHT/2.0, 0.1, 0.4);
		MeshShape *waistgeometry = new MeshShape(waist, waistGeomMesh);
		waist->geometry = waistgeometry;
		waist->appearance = waistappearance;
		//waist->appearance = new MeshAppearance(waistGeomMesh);
		vectorSet(waist->position, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT/2.0), 0);
		waist->setGravity(true);
		waist->setMass(2*WAISTHEIGHT/3.0);
		waist->setCollisionGroup(collisiongroup);
	}
	
	
	//Torso
	{
		torso = new BodyPart(this, 4);
    Mesh* torsoMesh = loadAscModel((char*)TORSOASC, TORSOSCALE);
		//int i;
		//for (i = 0; i < torsoMesh->polygoncount; i++) torsoMesh->polygons[i].smooth = false;
    MeshAppearance* torsoAppearance = new MeshAppearance(torsoMesh);
		torsoAppearance->material.setColor(torsocolor[0], torsocolor[1], torsocolor[2], 1);
		Mesh *torsoGeomMesh = createBox(-1, 1, -BLOCKHEIGHT*TORSOHEIGHT/2.0, BLOCKHEIGHT*TORSOHEIGHT/2.0, -0.5, 0.5);
		MeshShape *torsogeometry = new MeshShape(torso, torsoGeomMesh);
		torso->geometry = torsogeometry;
		torso->appearance = torsoAppearance;
		//torso->appearance = new MeshAppearance(torsoGeomMesh);
		vectorSet(torso->position, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT/2.0), 0);
		torso->setGravity(true);
		torso->setMass(2*TORSOHEIGHT/3.0);
		torso->setCollisionGroup(collisiongroup);
	}
	

	//Hands
	//Mesh *handMeshGeom = createBox(-0.4, 0.4, -BLOCKHEIGHT*HANDHEIGHT/2.0, BLOCKHEIGHT*HANDHEIGHT/2.0, -0.5, 0.5);
	Mesh *handMeshGeom = createBox(-0.2, 0.2, -BLOCKHEIGHT*HANDHEIGHT/2.0, BLOCKHEIGHT*HANDHEIGHT/2.0, -0.5, 0.5);


	//Left hand
	{
		lefthand = new BodyPart(this, 5);
		
    Mesh* leftHandMesh = loadAscModel((char*)LEFTARMASC, MODELSCALE, leftHandOffset);
		Mesh* leftPalmMesh = loadAscModel((char*)LEFTPALMASC, MODELSCALE, leftPalmOffset);
		MultiAppearance *a = new MultiAppearance();
		Appearance *arm = new MeshAppearance(leftHandMesh);
		Appearance *palm = new MeshAppearance(leftPalmMesh);
		arm->material.setColor(torsocolor[0], torsocolor[1], torsocolor[2], 1);
		palm->material.setColor(1, 1, 0, 1);
		a->addAppearance(arm);
		a->addAppearance(palm);
		MeshShape *lefthandgeometry = new MeshShape(lefthand, handMeshGeom);
		lefthand->geometry = lefthandgeometry;
		lefthand->appearance = a;//new MeshAppearance(leftHandMesh);
		//lefthand->appearance = new MeshAppearance(handMeshGeom);
		//lefthand->appearance->material.setColor(1, 0, 0, 1);
		vectorSet(lefthand->position, -1.3, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT - HANDHEIGHT/2.0), 0);
		lefthand->setGravity(true);
		lefthand->setMass(HANDHEIGHT/3.0);
		lefthand->setCollisionGroup(collisiongrouphand);
	}

	//Right hand
	{
		righthand = new BodyPart(this, 5);
    Mesh* rightHandMesh = loadAscModel((char*)RIGHTARMASC, MODELSCALE, rightHandOffset);
		Mesh* rightPalmMesh = loadAscModel((char*)RIGHTPALMASC, MODELSCALE, rightPalmOffset);
		MultiAppearance *a = new MultiAppearance();
		Appearance *arm = new MeshAppearance(rightHandMesh);
		arm->material.setColor(torsocolor[0], torsocolor[1], torsocolor[2], 1);
		Appearance *palm = new MeshAppearance(rightPalmMesh);
		palm->material.setColor(1, 1, 0, 1);
		a->addAppearance(arm);
		a->addAppearance(palm);
		MeshShape *righthandgeometry = new MeshShape(righthand, handMeshGeom);
		righthand->geometry = righthandgeometry;
		righthand->appearance = a;
		//righthand->appearance = new MeshAppearance(handMeshGeom);
		vectorSet(righthand->position, 1.3, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT - HANDHEIGHT/2.0), 0);
		righthand->setGravity(true);
		righthand->setMass(HANDHEIGHT/3.0);
		righthand->setCollisionGroup(collisiongrouphand);
	}
	
	
	//Head
	{
		head = new BodyPart(this, 2);
		Appearance *headappearance = new HeadAppearance();
		float r = BLOCKHEIGHT*HEADHEIGHT/2;
		/*SphereAppearance *headappearance = new SphereAppearance();
		headappearance->setRadius(r);
		headappearance->material.setColor(1, 1, 0, 1);*/
		SphereShape *headgeometry = new SphereShape(head);
		headgeometry->setRadius(r);
		head->geometry = headgeometry;
		head->appearance = headappearance;
		vectorSet(head->position, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT + HEADHEIGHT/2 + 0.5), 0);
		head->setGravity(true);
		head->setMass(4.0/3*PI*r*r*r);
		head->setCollisionGroup(collisiongroup);
	}


	headsensor = new Sensor();
	torsosensor = new Sensor();



	headvisual = new DamageVisual(head, damageHead, false,
		-0.5, -2, 0.5, -1);
	
	torsovisual = new DamageVisual(torso, damageTorso, false,
		-0.5, -1, 0.5, 0);
	
	lefthandvisual = new DamageVisual(lefthand, damageHand, true,
		0.4, -1, 0.9, 0);
	
	righthandvisual = new DamageVisual(righthand, damageHand, true,
		-0.4, -1, -0.9, 0);
	
	leftlegvisual = new DamageVisual(leftleg, damageLeg, true,
		0, 0, 0.5, 1);
	
	rightlegvisual = new DamageVisual(rightleg, damageLeg, true,
		-0, 0, -0.5, 1);


	harmfulobjects = NULL;


	walkphase = 0;
	jumpphase = 0;
	hitside = 0;

	alive = true;
}

void Legoman::insertToWorld(World *world){
	this->world = world;


	world->addChild(rightleg);
	world->addChild(leftleg);
	world->addChild(waist);
	world->addChild(torso);
	world->addChild(lefthand);
	world->addChild(righthand);
	world->addChild(head);
	float linkpoint[3];

	vectorSet(linkpoint, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT + HEADHEIGHT), 0);
	headlinks[0] = world->addLink(head, torso, linkpoint);

	vectorSet(linkpoint, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT), 0);
	headlinks[1] = world->addLink(head, torso, linkpoint);

	vectorSet(linkpoint, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT + HEADHEIGHT*0.5), 1);
	headlinks[2] = world->addLink(head, torso, linkpoint);

	head->attached = true;


	vectorSet(linkpoint, -1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT) - 0.5, 0);
	lefthandlinks[0] = world->addLink(torso, lefthand, linkpoint);

	vectorSet(linkpoint, -2, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT) - 0.5, 0);
	lefthandlinks[1] = world->addLink(torso, lefthand, linkpoint);

	lefthand->attached = true;


	vectorSet(linkpoint, 1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT) - 0.5, 0);
	righthandlinks[0] = world->addLink(torso, righthand, linkpoint);

	vectorSet(linkpoint, 2, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT) - 0.5, 0);
	righthandlinks[1] = world->addLink(torso, righthand, linkpoint);

	righthand->attached = true;


	vectorSet(linkpoint, -1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT), -0.5);
	world->addLink(torso, waist, linkpoint);

	vectorSet(linkpoint, 1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT), -0.5);
	world->addLink(torso, waist, linkpoint);

	vectorSet(linkpoint, -1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT), 0.5);
	world->addLink(torso, waist, linkpoint);

	vectorSet(linkpoint, 1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT), 0.5);
	world->addLink(torso, waist, linkpoint);

	waist->attached = true;


	vectorSet(linkpoint, -1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT)-0.5, 0);
	leftleglinks[0] = world->addLink(waist, leftleg, linkpoint);

	vectorSet(linkpoint, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT)-0.5, 0);
	leftleglinks[1] = world->addLink(waist, leftleg, linkpoint);
	
	lll = leftleglinks[1];

	leftleg->attached = true;


	vectorSet(linkpoint, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT)-0.5, 0);
	rightleglinks[0] = world->addLink(waist, rightleg, linkpoint);

	vectorSet(linkpoint, 1, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT)-0.5, 0);
	rightleglinks[1] = world->addLink(waist, rightleg, linkpoint);

	rll = rightleglinks[0];

	rightleg->attached = true;


	leftleglinks[2] = world->addLink(waist, leftleg, NULL);
	leftleglink = leftleglinks[2];
	leftleglink->enabled = false;
	rightleglinks[2] = world->addLink(waist, rightleg, NULL);
	rightleglink = rightleglinks[2];
	rightleglink->enabled = false;

	lefthandlinks[2] = world->addLink(torso, lefthand, NULL);
	lefthandlink = lefthandlinks[2];
	lefthandlink->enabled = false;
	righthandlinks[2] = world->addLink(torso, righthand, NULL);
	righthandlink = righthandlinks[2];
	righthandlink->enabled = false;
}

void Legoman::heal(void){
	headlinks[0]->enabled = true;
	headlinks[1]->enabled = true;
	headlinks[2]->enabled = true;
	lefthandlinks[0]->enabled = true;
	lefthandlinks[1]->enabled = true;
	lefthandlinks[2]->enabled = true;
	righthandlinks[0]->enabled = true;
	righthandlinks[1]->enabled = true;
	righthandlinks[2]->enabled = true;
	leftleglinks[0]->enabled = true;
	leftleglinks[1]->enabled = true;
	leftleglinks[2]->enabled = true;
	rightleglinks[0]->enabled = true;
	rightleglinks[1]->enabled = true;
	rightleglinks[2]->enabled = true;

	leftleglink->enabled = false;
	rightleglink->enabled = false;
	lefthandlink->enabled = false;
	righthandlink->enabled = false;

	leftleg->reset();
	rightleg->reset();
	waist->reset();
	torso->reset();
	lefthand->reset();
	righthand->reset();
	head->reset();
	vectorSet(leftleg->position, -0.6, BLOCKHEIGHT*(LEGHEIGHT/2.0), 0);
	vectorSet(rightleg->position, 0.6, BLOCKHEIGHT*(LEGHEIGHT/2.0), 0);
	vectorSet(waist->position, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT/2.0), 0);
	vectorSet(torso->position, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT/2.0), 0);
	vectorSet(lefthand->position, -1.3, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT - HANDHEIGHT/2.0), 0);
	vectorSet(righthand->position, 1.3, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT - HANDHEIGHT/2.0), 0);
	vectorSet(head->position, 0, BLOCKHEIGHT*(LEGHEIGHT + WAISTHEIGHT + TORSOHEIGHT + HEADHEIGHT/2 + 0.5), 0);

	headsensor->attach(head);
	torsosensor->attach(torso);

	alive = true;
}

void Legoman::lockPart(int part){
	if (part & LEFTLEG && leftleg->energy > 0){
		float linkpoint[3];
		vectorScale(linkpoint, &leftleg->rotation[3], -1);
		//vectorAdd(linkpoint, leftleg->position);
		vectorAdd(linkpoint, waist->position);
		vectorAdd(linkpoint, lll->point1);
		world->renewLink(leftleglink, linkpoint);
	}
	if (part & RIGHTLEG && rightleg->energy > 0){
		float linkpoint[3];
		vectorScale(linkpoint, &rightleg->rotation[3], -1);
		//vectorAdd(linkpoint, rightleg->position);
		vectorAdd(linkpoint, waist->position);
		vectorAdd(linkpoint, rll->point1);
		world->renewLink(rightleglink, linkpoint);
	}
	if (part & LEFTHAND && lefthand->energy > 0){
		float linkpoint[3];
		vectorScale(linkpoint, &lefthand->rotation[3], -1);
		vectorAdd(linkpoint, lefthand->position);
		world->renewLink(lefthandlink, linkpoint);
	}
	if (part & RIGHTHAND && righthand->energy > 0){
		float linkpoint[3];
		vectorScale(linkpoint, &righthand->rotation[3], -1);
		vectorAdd(linkpoint, righthand->position);
		world->renewLink(righthandlink, linkpoint);
	}

	headsensor->attach(head);
	torsosensor->attach(torso);
}

void Legoman::addHarmfulObject(Object *object){
	objectlist *node = new objectlist();
	node->object = object;
	node->next = harmfulobjects;
	harmfulobjects = node;
}

bool Legoman::isHarmfulObject(Object *object){
	objectlist *node = harmfulobjects;
	while (node != NULL){
		if (node->object == object) return true;
		node = node->next;
	}
	return false;
}

float Legoman::getInvMass(void){
	float mass = torso->getMass() + waist->getMass();
	if (head->attached) mass += head->getMass();
	if (lefthand->attached) mass += lefthand->getMass();
	if (righthand->attached) mass += righthand->getMass();
	if (leftleg->attached) mass += leftleg->getMass();
	if (rightleg->attached) mass += rightleg->getMass();
	return 1.0/mass;
}

void Legoman::addOpponent(Legoman *opponent){
	this->opponent = opponent;
	opponent->addHarmfulObject(head);
	opponent->addHarmfulObject(lefthand);
	opponent->addHarmfulObject(righthand);
	opponent->addHarmfulObject(leftleg);
	opponent->addHarmfulObject(rightleg);
}

void Legoman::unlockPart(int part){
	if (part & LEFTLEG){
		leftleglink->enabled = false;
	}
	if (part & RIGHTLEG){
		rightleglink->enabled = false;
	}
	if (part & LEFTHAND){
		lefthandlink->enabled = false;
	}
	if (part & RIGHTHAND){
		righthandlink->enabled = false;
	}
}

void Legoman::move(float *movement){
	vectorAdd(leftleg->position, movement);
	vectorAdd(rightleg->position, movement);
	vectorAdd(waist->position, movement);
	vectorAdd(torso->position, movement);
	vectorAdd(lefthand->position, movement);
	vectorAdd(righthand->position, movement);
	vectorAdd(head->position, movement);
}

#define LEGSPEED 0.03

#define BALANCEANGLE (PI/12)

void Legoman::balance(void){
	if (!alive || !head->attached) return;

	float headpos[3], torsopos[3];
	headsensor->getPosition(headpos);
	torsosensor->getPosition(torsopos);
	float posdiff[3];
	vectorSub(posdiff, headpos, torsopos);
	float posdifflen = vectorLength(posdiff);
	float angle = acos(posdiff[1]/posdifflen);

	float headtarget[3];
	vectorSet(headtarget, 0, posdifflen, 0);
	vectorAdd(headtarget, torsopos);

	float force[3];
	vectorSub(force, headtarget, headpos);

	float headvel[3], torsovel[3];
	headsensor->getVelocity(headvel);
	torsosensor->getVelocity(torsovel);
	float veldiff[3];
	vectorSub(veldiff, headvel, torsovel);
	vectorScale(veldiff, 50);

	vectorSaturate(veldiff, 0, 10);

	vectorSub(force, veldiff);

	if (angle < BALANCEANGLE){
		vectorScale(force, pow(1-angle/BALANCEANGLE, 0.1));
		vectorScale(force, 100);
		head->addExternalForce(force);
	}

	if (walkdelay == 0){
		if (walkphase > 0){
			walkphase --;
			updateLegs();
		}
	}

	vectorScale(lefthand->angularmomentum, 0.98);
	vectorScale(righthand->angularmomentum, 0.98);
}

void Legoman::update(void){
	if (walkdelay > 0){
		walkdelay--;
	}

	/*if (jumpphase > 0){
		jumpphase--;
	}*/
	if (torso->momentum[1] < 0 && isOnGround()){
		jumpphase--;
		if (jumpphase == 0) jumpenabled = true;
	}

	if (hitside < 10) hitside += 2;
	//hitside = -hitside;
	/*if (hitside > 0){
		hitside = -hitside;
	}/* else{
		hitside = 0;
	}*/

	if (alive){
		if (head->position[1] < 0){// && torso->momentum[1] < 0){
			fallOff();
		}

		headsensor->update();
		torsosensor->update();

		balance();
	}
}

void Legoman::updateLegs(void){
	float temp[3];
	float angle;

	walkphase = sfmod(walkphase, PI/LEGSPEED);

	//Left leg
	angle = sfmod(walkphase*LEGSPEED, PI);
	if (angle > PI/4) angle = PI/2 - angle;
	if (angle < -PI/4) angle = -PI/2 - angle;
	vectorSet(temp, 0, -cos(angle), -sin(angle));
	vectorAdd(temp, lll->point1);
	vectorCopy(leftleglink->point1, temp);

	//Right leg
	angle = sfmod(walkphase*LEGSPEED + PI/2, PI);
	if (angle > PI/4) angle = PI/2 - angle;
	if (angle < -PI/4) angle = -PI/2 - angle;
	vectorSet(temp, 0, -cos(angle), -sin(angle));
	vectorAdd(temp, rll->point1);
	vectorCopy(rightleglink->point1, temp);
}

void Legoman::walk(float amount){
	walkdelay = 20;

	float sign;
	if (amount > 0) sign = 1;
	else sign = -1;

	walkphase += sign;

	updateLegs();

	if (!isStanding()) return;

	float movement[3];
	float xdir[3], ydir[3], zdir[3];

	//vectorScale(ydir, &torso->rotation[3], 1);
	vectorSet(ydir, 0, 1, 0);
	vectorScale(zdir, &torso->rotation[6], -1);
	vectorCross(xdir, ydir, zdir);
	vectorNormalize(xdir);
	//vectorScale(xdir, &torso->rotation[0], 1);

	float oldmomentum[3];
	vectorCopy(oldmomentum, torso->momentum);

	float xmove[3], ymove[3], zmove[3];

	vectorProject(xmove, oldmomentum, xdir);
	vectorProject(ymove, oldmomentum, ydir);
	vectorProject(zmove, oldmomentum, zdir);

	vectorScale(xmove, 0.5);
	float wh = waist->position[1];
	if (wh < WAISTHEIGHT + 1.0){
		float hd = WAISTHEIGHT + 1.0 - wh;
		vectorScale(ymove, ydir, hd*10);
	}
	float newz[3];
	vectorScale(newz, zdir, 6*sign);
	float ztemp[3];
	vectorProject(ztemp, newz, ydir);
	vectorSub(newz, ztemp);
	vectorScale(newz, 0.8);
	vectorScale(zmove, 0.2);
	vectorAdd(zmove, newz);

	vectorCopy(movement, xmove);
	vectorAdd(movement, ymove);
	vectorAdd(movement, zmove);

	//if (isStanding() && isOnGround())

	vectorCopy(torso->momentum, movement);
	vectorScale(movement, torso->invmass*waist->getMass());
	vectorCopy(waist->momentum, movement);


	/*float speed = vectorDot(oldmomentum, movement);
	float speedadd = 1;
	float maxspeed = 5;
	/*speed += speedadd;
	if (speed > maxspeed) speed = maxspeed;
	if (speed + speedadd > maxspeed){
		speedadd = maxspeed - speed;
	}

	vectorScale(movement, speedadd);
	if (waist->position[1] < WAISTHEIGHT + 1.0){
		movement[1] = 3;
	}
	vectorAdd(torso->momentum, movement);*/

		/*float proj[3];
		vectorProject(proj, oldmomentum, movement);
		float len = vectorLength(proj);
		vectorAdd(movement, proj);
		vectorSaturate(movement, 0, 
		
		movement[1] = 300;
		//torso->addExternalForce(movement);
	}*/
	
	/*float linkpoint[3];
	vectorScale(linkpoint, &leftleg->rotation[3], -1);
	vectorAdd(linkpoint, leftleg->position);*/

		/*float movement[3];
	float temp[3];
	vectorScale(temp, &torso->rotation[3], amount*0.1);
	vectorScale(movement, &torso->rotation[6], amount);
	vectorAdd(movement, temp);

	if (walkphase == 0){
		walkphase = 40;
		vectorAdd(leftleg->momentum, movement);
	}
	if (walkphase == 20){
		walkphase = 19;
		vectorAdd(rightleg->momentum, movement);
	}*/

	/*float axis[3];
	vectorScale(axis, &leftleg->rotation[0], amount);

	if (walkphase == 0){
		//walkphase = 40;
		vectorAdd(leftleg->angularmomentum, axis);
		vectorAdd(rightleg->angularmomentum, axis);
	}*/
	/*if (walkphase == 0){
		walkphase = 1;
		vectorAdd(rightleg->momentum, movement);
	}*/
	/*float axis[3];
	float movement[3];

	if (walkphase == 0){
		unlockPart(LEFTLEG);

		vectorScale(axis, &leftleg->rotation[0], 5);
		vectorAdd(leftleg->angularmomentum, axis);
		
		float temp[3];
		vectorScale(temp, &torso->rotation[6], -10);
		vectorScale(movement, &torso->rotation[3], 5);
		vectorAdd(movement, temp);
		vectorAdd(torso->momentum, movement);
		vectorAdd(leftleg->momentum, movement);

		walkphase = 40;
	}*/
}

void Legoman::turn(float amount){
	float axis[3];
	if (isStanding()){
		vectorScale(axis, &torso->rotation[3], amount);
		vectorCopy(torso->angularmomentum, axis);
	} else{
		vectorScale(axis, &torso->rotation[3], amount*0.3);
		vectorAdd(torso->angularmomentum, axis);
	}
}

void Legoman::hit(void){
	if (!lefthand->attached && !righthand->attached) return;
	/*float leftdot = vectorDot(&lefthand->rotation[3], &torso->rotation[6]);
	float rightdot = vectorDot(&righthand->rotation[3], &torso->rotation[6]);
	if (leftdot < rightdot){
		hitside = LEFTHAND;
	} else{
		hitside = RIGHTHAND;
	}*/

	if (hitside >= 10) hitside -= 9;
	else hitside -= 2;

	if ((hitside & 1) && !lefthand->attached) hitside++;
	if (!(hitside & 1) && !righthand->attached) hitside++;

	float axis[3];
	if (hitside & 1){
		vectorScale(axis, &lefthand->rotation[0], 20);
		vectorCopy(lefthand->angularmomentum, axis);
	} else{
		vectorScale(axis, &righthand->rotation[0], 20);
		vectorCopy(righthand->angularmomentum, axis);
	}
}

void Legoman::jump(void){
	if (!leftleg->attached && !rightleg->attached) return;
	if (jumpenabled){// == 0 && isOnGround()){
		float r = BLOCKHEIGHT*HEADHEIGHT/2;
		float strength = (2*LEGHEIGHT + 2*WAISTHEIGHT + 2*TORSOHEIGHT
			+ 2*HANDHEIGHT + 4.0*PI*r*r*r)/3.0*getInvMass();
		float jumpvector[3] = {0, 100.0/strength, 0};

		//vectorCopy(torso->momentum, jumpvector);
		torso->momentum[1] = jumpvector[1];
		head->momentum[1] = 0;// jumpvector[1];
		waist->momentum[1] = 0;// jumpvector[1];
		leftleg->momentum[1] = 0;// jumpvector[1];
		rightleg->momentum[1] = 0;// jumpvector[1];
		lefthand->momentum[1] = 0;// jumpvector[1];
		righthand->momentum[1] = 0;// jumpvector[1];
		//vectorSet(head->momentum, 0, 0, 0);
		//jumpphase = 150;
		jumpsound->play();
		jumpenabled = false;
	}
	jumpphase = 2;
}

bool Legoman::isOnGround(void){
	//if (!isStanding()) return false;
	float wh = waist->position[1];
	if (wh > WAISTHEIGHT + 1.5) return false;
	if (fabs(torso->momentum[1]) > 10) return false;
	//if (fabs(head->momentum[1]) > 10) return false;
	//if (fabs(waist->momentum[1]) > 3) return false;
	return true;
}

bool Legoman::isStanding(void){
	if (!leftleg->attached && !rightleg->attached) return false;
	float headpos[3], torsopos[3];
	headsensor->getPosition(headpos);
	torsosensor->getPosition(torsopos);
	float posdiff[3];
	vectorSub(posdiff, headpos, torsopos);
	float posdifflen = vectorLength(posdiff);
	float angle = acos(posdiff[1]/posdifflen);

	if (angle < BALANCEANGLE) return true;
	else return false;
}

void Legoman::fallOff(void){
	if (dead) return;
	if (rand()&1) fallsound1->play();
	else fallsound2->play();
	die();
	head->energy = 0;
	torso->energy = 0;
	lefthand->energy = 0;
	righthand->energy = 0;
	waist->energy = 0;
	leftleg->energy = 0;
	rightleg->energy = 0;
}

void Legoman::releasePart(BodyPart *part){
	if (dead) return;
	if (part == head){
		headlinks[0]->enabled = false;
		headlinks[1]->enabled = false;
		headlinks[2]->enabled = false;
		head->attached = false;
		//float move[3];
		//vectorScale(move, &head->rotation[3], 1);
		//vectorAdd(head->position, move);
		die();
	} else if (part == lefthand){
		lefthandlinks[0]->enabled = false;
		lefthandlinks[1]->enabled = false;
		lefthandlinks[2]->enabled = false;
		lefthand->attached = false;
	} else if (part == righthand){
		righthandlinks[0]->enabled = false;
		righthandlinks[1]->enabled = false;
		righthandlinks[2]->enabled = false;
		righthand->attached = false;
	} else if (part == leftleg){
		leftleglinks[0]->enabled = false;
		leftleglinks[1]->enabled = false;
		leftleglinks[2]->enabled = false;
		leftleg->attached = false;
	} else if (part == rightleg){
		rightleglinks[0]->enabled = false;
		rightleglinks[1]->enabled = false;
		rightleglinks[2]->enabled = false;
		rightleg->attached = false;
	} else if (part == torso){
		die();
	}
	if (!lefthand->attached && !righthand->attached &&
			!leftleg->attached && !rightleg->attached) die();
}

void Legoman::die(void){
	if (dead) return;
	alive = false;
	lll->enabled = false;
	rll->enabled = false;
	gameOver(this);
}

bool Legoman::isAlive(void){
	return alive;
}

Legoman *Legoman::getOpponent(void){
	return opponent;
}

void Legoman::drawVisuals(void){
	headvisual->draw();
	torsovisual->draw();
	lefthandvisual->draw();
	righthandvisual->draw();
	leftlegvisual->draw();
	rightlegvisual->draw();
}



DamageVisual::DamageVisual(BodyPart *object, Texture *texture, bool mirror,
													 float x1, float y1, float x2, float y2){
	this->object = object;
	this->texture = texture;

	this->x1 = x1;
	this->y1 = y1;
	this->x2 = x2;
	this->y2 = y2;

	float d = 3.0/512;

	if (mirror){
		this->tx1 = 1-d;
		this->tx2 = 0+d+0.01;
	} else{
		this->tx1 = 0+d+0.01;
		this->tx2 = 1-d;
	}
	this->ty1 = 0+d;
	this->ty2 = 1-d;
}

void DamageVisual::draw(void){
	float energy = object->energy;
	texture->enable();

	glBegin(GL_QUADS);
		if (energy > 0)	glColor3f(1-energy, energy, 0);
		else glColor3f(0.3, 0.3, 0.3);

		glTexCoord2f(tx1, ty1);
		glVertex2f(x1, y1);
		
		glTexCoord2f(tx1, ty2);
		glVertex2f(x1, y2);
		
		glTexCoord2f(tx2, ty2);
		glVertex2f(x2, y2);
		
		glTexCoord2f(tx2, ty1);
		glVertex2f(x2, y1);
	glEnd();
}
