// SoccerBot
// Versión 0.0.3
//
// Explicación
// ===========
//
// Busca la posición de la pelota y la portería izquierda y calcula
// la trayectoria que debe seguir el robot para golpear a la pelota
// en el punto correcto para dirigirla hacia la portería.
// 
// El bot reacciona a comandos de voz por lo que no comenzará a
// jugar hasta decir "begin" en el canal principal de comunicación
// y no se detendrá hasta pronunciar "end". También reconoce los
// comandos "pause" y "continue".
//
// Problemas
// =========
//
// Si el punto de la pelota que intentamos golpear está en la parte
// de "atrás", desde el punto de vista del robot, lo golpeará por el
// lado contrario, por "delante", enviándola en la dirección
// contraria a la deseada.
//
// Próxima tarea
// =============
// 
// [1]
// Construir dos bots que se comuniquen entre sí para determinar cual
// es el robot más cercano a la pelota y ese ser el que la golpee mientras
// el otro busca una posición adelantada para rematar el golpe.
//
// [2]
// Permitir la configuración de la portería a la que debe de marcar gol.
//
// [3]
// Marcar una posición inicial a la que debe de acudir una vez se haya
// marcado un gol.
//
//
// Utilización del script
// ======================
//
// Para poder probar el script es necesario disponer de un campo adecuado
// así como una pelota. Estos elementos se pueden encontrar en el sandbox
// de la isla de la ESEI en Second Life (Quest I (151, 82, 28)).
// 
// Crea un cilindro con las dimensiones (0.5, 0.5, 0.25) activando la 
// etiqueta "Physics" y eligiendo como material "metal".
// 
// Sitúa el bot en el campo.
//
// Comandos de voz
// ===============
//
// "begin": Inicia el juego, el robot guarda la posición de la portería
//         y se pasa a modo "playing". durante el juego busca la pelota
//         de forma continua para golpearla hacia la portería.
//
// "end": Deniene el bot y lo prepara para poder iniciar un nuevo partido.
//
// "pause": Deniene el bot temporalmente.
//
// "continue": Retorna al bot al juego después de una pausa.
//
// Otras notas
// ===========
//
// Cualquier modificación es bienvenida. Puedes contactar conmigo en
// mailoyo /arroba/ gmail /punto/ com

// Constantes
integer SENSOR_NONE = 0;
integer SENSOR_BALL = 1;
integer SENSOR_GOAL = 2;

vector ballPos; // Posición de la pelota
vector goalPos; // Posición de la portería (en la que tenemos que meter)

integer sensorFor = SENSOR_NONE; // Para saber que estamos buscando con el sensor

shot()
{
	// Vector de la pelota hacia la portería
    vector vBallGoal = goalPos - ballPos; 
    // Normalizado
    vector vBallGoalN = llVecNorm(vBallGoal); 
    // Punto al que debemos golpear la pelota
    vector vBallPoint = ballPos + vBallGoalN * -0.5; 
    vector v = llVecNorm(vBallPoint - llGetPos());
    llApplyImpulse(v*2, 0);
}

default
{
    state_entry()
    {
		llListen(0, "", NULL_KEY, "begin");
    }

	listen(integer channel, string name, key id, string message)
	{
		state init;
	}
}

state init
{
	state_entry()
    {
		// Buscamos la portería
		llSensor("LeftGoal", NULL_KEY, ACTIVE | PASSIVE, 15, PI);
		
		// Empezamos a jugar
		state playing;
    }

	sensor(integer numberDetected)
    {
		goalPos = llDetectedPos(0);
    }
}

state paused
{
	state_entry()
	{
		// Escuchamos comandos
		llListen(0, "", NULL_KEY, "");
	}
	
	listen(integer channel, string name, key id, string message)
	{
		if (message == "continue")
		{
			state playing;
		}
	}
}

state playing
{
	state_entry()
    {
		// Buscamos la pelota cada 2 segundos
		sensorFor = SENSOR_BALL;
        llSensorRepeat("Pelota", NULL_KEY, ACTIVE | PASSIVE, 15, PI, 2.0);

		// Escuchamos comandos de voz
		llListen(0, "", NULL_KEY, "");
    }
    
    sensor(integer numberDetected)
    {
        if (sensorFor == SENSOR_BALL)
		{
			ballPos = llDetectedPos(0);
			shot();
		}
    }
    
    no_sensor()
    {
    }

	listen(integer channel, string name, key id, string message)
	{
		// Comandos de voz
		if (message == "end")
		{
			llSensorRemove();
			state default;
		}
		else if (message == "pause")
		{
			llSensorRemove();
			state paused;
		}
	}
}
