/*  The Blue Mango Quest
 *  Copyright (c) Clément 'phneutre' Bourdarias (code)
 *                   email: phneutre@users.sourceforge.net
 *                Guillaume 'GuBuG' Burlet (graphics)
 *                   email: gubug@users.sourceforge.net
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glu.h>
#include <SDL/SDL.h>

#ifdef HAVE_SDL_MIXER
# include <SDL/SDL_mixer.h>
#endif

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "world_building.h"
#include "map.h"
#include "timers.h"
#include "world_geometry.h"
#include "hut.h"
#include "bonus.h"
#include "mango.h"
#include "game_loop.h"
#include "system_gl.h"
#include "draw_scene_gl.h"
#include "sector.h"
#include "move.h"
#include "hud.h"
#include "sounds.h"

extern game_data_t *world;
extern player_t *player;

void rotate (double factor)
{
  double vitesse;

  if (!player->run)
    vitesse = (double) player->rotat_speed[0] * world->game_sync->dt*factor;

  else
    vitesse = (double) player->rotat_speed[1] * world->game_sync->dt*factor;

  if (player->y_rot >= vitesse)
    player->y_rot -= vitesse;
  else
    player->y_rot = 360 - (vitesse - player->y_rot);

  player->u.x = -sin(player->y_rot * pi_sur_180);
  player->u.z = -cos(player->y_rot * pi_sur_180);

}

void move_forward()
{
  double vitesse = 0;
  double delta_x = 0, delta_z = 0;
  int avancerHor = 0, avancerVert = 0;
  int test_square=0;

  double test_pos_x=0, test_pos_z=0;
  int test_map_x=0, test_map_z=0;

  if (!player->run)
    vitesse = player->trans_speed[0] * world->game_sync->dt;
  else
    vitesse = player->trans_speed[1] * world->game_sync->dt;

  delta_x = (double) sin(player->y_rot * pi_sur_180) * vitesse;
  delta_z = (double) cos(player->y_rot * pi_sur_180) * vitesse;

  /* changed */

  test_pos_x = player->pos_x-delta_x;
  test_map_x = (int) floor(test_pos_x / SCALE_FACTOR);
  
  test_pos_z = player->pos_z-delta_z;
  test_map_z = (int) floor(test_pos_z / SCALE_FACTOR);
  
  test_square = map_to_square(test_map_x, test_map_z);
  if (test_square != player->square) {

    /*printf("player on %d, tested %d\n",player->square,test_square);
    if (test_square==get_left(player->square)) printf("(it was on the left\n");
    else if (test_square==get_right(player->square)) printf("(it was on the right\n");
    else if (test_square==get_up(player->square)) printf("(it was on the up\n");

    else if (test_square==get_down(player->square)) printf("(it was on the down\n");

    else printf("(it was horrible\n"); */

    if ((test_square != get_left(player->square)) 
	&& (test_square != get_right(player->square))
	&& (test_square != get_up(player->square))
	&& (test_square != get_down(player->square)))
      {
	//printf("OUCH! player on %d, tested %d\n",player->square,test_square);
	return;
      }
  }
  
  /* end change */

  test_square = map_to_square(player->map_x, player->map_z);

  if (delta_x >= 0) /* we go left */
  {                             
    if (test_left(test_square))
    {
      /* there is something on the left, compute the distance */
      if ((player->pos_x-vitesse) - player->map_x * SCALE_FACTOR < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  else if (delta_x < 0) /* we go right */
  {
    if (test_right(test_square))
    {
      if ((player->map_x + 1) * SCALE_FACTOR - (player->pos_x+vitesse) < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  if (delta_z >= 0) /* we go up */
  {
    if (test_up(test_square))
    {
      if ((player->pos_z-vitesse) - player->map_z * SCALE_FACTOR < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  else if (delta_z < 0)
  {                             // on va vers le bas
    // il y a qqch à droite
    if (test_down(test_square))
    {
      if ((player->map_z + 1) * SCALE_FACTOR - (player->pos_z+vitesse) < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  if (avancerHor)
  {
    player->pos_x -= delta_x;
    player->map_x = (int) floor(player->pos_x / SCALE_FACTOR);
  }

  if (avancerVert)
  {
    player->pos_z -= delta_z;
    player->map_z = (int) floor(player->pos_z / SCALE_FACTOR);
  }

  player->square = map_to_square(player->map_x, player->map_z);
}

void move_backward()
{

  double vitesse = 0;
  double delta_x = 0, delta_z = 0;
  int avancerHor = 0, avancerVert = 0;
  int test_square=0;

  if (!player->run)
    vitesse = player->trans_speed[0] * world->game_sync->dt;
  else
    vitesse = player->trans_speed[1] * world->game_sync->dt;

  delta_x = (double) sin(player->y_rot * pi_sur_180) * vitesse;
  delta_z = (double) cos(player->y_rot * pi_sur_180) * vitesse;

  test_square = map_to_square(player->map_x, player->map_z);

  if (delta_x < 0)
  {                             // on va vers la gauche
    // il y a qqch à gauche
    if (test_left(test_square))
    {
      if (player->pos_x - player->map_x * SCALE_FACTOR < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  else if (delta_x >= 0)
  {                             // on va vers la droite
    // il y a qqch à droite
    if (test_right(test_square))
    {
      if ((player->map_x + 1) * SCALE_FACTOR - player->pos_x < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  if (delta_z < 0)
  {                             // on va vers le haut
    if (test_up(test_square))
    {
      if (player->pos_z - player->map_z * SCALE_FACTOR < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  else if (delta_z >= 0)
  {                             // on va vers le bas
    // il y a qqch à droite
    if (test_down(test_square))
    {
      if ((player->map_z + 1) * SCALE_FACTOR - player->pos_z < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  if (avancerHor)
  {
    player->pos_x += delta_x;
    player->map_x = (int) floor(player->pos_x / SCALE_FACTOR);
  }

  if (avancerVert)
  {
    player->pos_z += delta_z;
    player->map_z = (int) floor(player->pos_z / SCALE_FACTOR);
  }

  player->square = map_to_square(player->map_x, player->map_z);
}

void look_around(char direction, double factor)
{
  if (direction == SHX_HAUT)
  {
    if (player->x_rot > -35)
      player->x_rot -= player->rotat_speed[1]* world->game_sync->dt*factor;
  }
  else if (direction == SHX_BAS)
  {
    if (player->x_rot < 45)
      player->x_rot += player->rotat_speed[1]* world->game_sync->dt*factor;
  }
  else if (direction == SHX_CENTRE)
    player->x_rot = 0.0f;
}

void move_slide_left()
{
  double vitesse = 0, delta_x = 0, delta_z = 0;
  double avancerHor = 0, avancerVert = 0;
  int test_square=0;

  if (!player->run)
    vitesse = player->trans_speed[0] * world->game_sync->dt;
  else
    vitesse = player->trans_speed[1] * world->game_sync->dt;

  delta_x = (double) cos(player->y_rot * pi_sur_180) * vitesse;
  delta_z = (double) sin(player->y_rot * pi_sur_180) * vitesse;

  test_square = map_to_square(player->map_x, player->map_z);

  if (delta_x >= 0)
  {                             // on va vers la gauche
    // il y a qqch à gauche
    if (test_left(test_square))
    {
      if (player->pos_x - player->map_x * SCALE_FACTOR < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  else if (delta_x < 0)
  {                             // on va vers la droite
    // il y a qqch à droite
    if (test_right(test_square))
    {
      if ((player->map_x + 1) * SCALE_FACTOR - player->pos_x < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  if (delta_z < 0)
  {                             // on va vers le haut
    if (test_up(test_square))
    {
      if (player->pos_z - player->map_z * SCALE_FACTOR < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  else if (delta_z >= 0)
  {                             // on va vers le bas
    // il y a qqch à droite
    if (test_down(test_square))
    {
      if ((player->map_z + 1) * SCALE_FACTOR - player->pos_z < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  player->slide = SHX_GAUCHE;

  if (avancerHor)
  {
    player->pos_x -= delta_x;
    player->map_x = (int) floor(player->pos_x / SCALE_FACTOR);
  }

  if (avancerVert)
  {
    player->pos_z += delta_z;
    player->map_z = (int) floor(player->pos_z / SCALE_FACTOR);
  }

  player->square = map_to_square(player->map_x, player->map_z);

}

void move_slide_right()
{
  double vitesse = 0, delta_x = 0, delta_z = 0;
  double avancerHor = 0, avancerVert = 0;
  int test_square=0;

  if (!player->run)
    vitesse = player->trans_speed[0] * world->game_sync->dt;
  else
    vitesse = player->trans_speed[1] * world->game_sync->dt;

  delta_x = (double) cos(player->y_rot * pi_sur_180) * vitesse;
  delta_z = (double) sin(player->y_rot * pi_sur_180) * vitesse;

  test_square = map_to_square(player->map_x, player->map_z);

  if (delta_x < 0)
  {                             // on va vers la gauche
    // il y a qqch à gauche
    if (test_left(test_square))
    {
      if (player->pos_x - player->map_x * SCALE_FACTOR < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  else if (delta_x >= 0)
  {                             // on va vers la droite
    // il y a qqch à droite
    if (test_right(test_square))
    {
      if ((player->map_x + 1) * SCALE_FACTOR - player->pos_x < DIST_MAXI)
        avancerHor = 0;
      else
        avancerHor = 1;
    }
    else
      avancerHor = 1;
  }

  if (delta_z >= 0)
  {                             // on va vers le haut
    if (test_up(test_square))
    {
      if (player->pos_z - player->map_z * SCALE_FACTOR < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  else if (delta_z < 0)
  {                             // on va vers le bas
    // il y a qqch à droite
    if (test_down(test_square))
    {
      if ((player->map_z + 1) * SCALE_FACTOR - player->pos_z < DIST_MAXI)
        avancerVert = 0;
      else
        avancerVert = 1;
    }
    else
      avancerVert = 1;
  }

  player->slide = SHX_DROITE;

  if (avancerHor)
  {
    player->pos_x += delta_x;
    player->map_x = (int) floor(player->pos_x / SCALE_FACTOR);
  }

  if (avancerVert)
  {
    player->pos_z -= delta_z;
    player->map_z = (int) floor(player->pos_z / SCALE_FACTOR);
  }

  player->square = map_to_square(player->map_x, player->map_z);
}

void teleport_to(int whereTo)
{
  play_misc_sound(S_TELEPORT);
  printf("Teleporting to square %d\n",whereTo);
  hud_new_message("You have been teleported");

  player->map_x = square_to_map_x(whereTo);
  player->map_z = square_to_map_z(whereTo);

  player->pos_x = player->map_x * SCALE_FACTOR + 1.5;
  player->pos_z = player->map_z * SCALE_FACTOR + 1.5;

  player->square = map_to_square(player->map_x, player->map_z);

  if (world->map[player->square].tex_mur > -1)
  {
    fprintf(stderr, "Error: wall on (%d,%d) (should not happen)\n",
            player->map_x, player->map_z);
    exit(1);
  }
}
