# Balazar
# Copyright (C) 2004 Jean-Baptiste LAMY
#
# 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 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

import math
import soya, tofu
from soya import Point, Vector

from balazar.character import *
from balazar.character import _P, _V
import balazar.globdef    as globdef

import balazar.base  as base



class Traveling(soya.ThirdPersonTraveling):
  def __init__(self, character, *args):
    soya.ThirdPersonTraveling.__init__(self, character, *args)
    
    self.character      = character
    self.enemy          = None
    self.next_enemy     = None
    self.fight_target   = None
    self.factor         = 1.0
    self.changing_side  = 0
    
    self.top_view       = 0.17
    self.distance       = 7.0
    self.offset_y       = 2.0
    self.offset_y2      = 1.0
    
  def is_in_fight_mode(self): return self.fight_target
  
  def set_enemy(self, enemy):
    if enemy and (self.character.distance_to(enemy) > 16.0): return
    
    if self.enemy:
      if not enemy is self.enemy:
        if enemy is None: self.next_enemy = 1
        else:             self.next_enemy = enemy
    else:
      self._set_enemy(enemy)
      
  def _set_enemy(self, enemy):
    if enemy:
      if not self.enemy:
        self.old_distance  = self.distance
        self.old_top_view  = self.top_view
        self.old_offset_y2 = self.offset_y2
        self.top_view      = 0.17
        self.lateral_angle = 0.0
      self.enemy          = enemy
      self.max_enemy_dist = max(10.0, 1.2 * self.character.distance_to(self.enemy))
      self.fight_target   = soya.Volume(self.character.parent)
      self.target         = soya.Volume(self.character.parent)
      self.ideal_ratio    = 10.0
    else:
      self.enemy        = None
      self.fight_target = None
      self.target       = self.character
      self.factor       = 1.0
      
      self.distance     = self.old_distance
      self.top_view     = self.old_top_view
      self.offset_y2    = self.old_offset_y2
      
  def best_position(self, camera):
    if not self.character.level: return camera

    for i in self.character.level.camera_can_pass_through:
      i.solid = 0
    
    if (not self.next_enemy) and self.enemy and ((getattr(self.enemy, "life", 1) <= 0) or (not self.enemy.parent) or (self.character.distance_to(self.enemy) > self.max_enemy_dist)):
      self.set_enemy(None)
      
    if self.fight_target:
      self.distance = 3.0 + self.character.distance_to(self.enemy)
      
      ff = 1.0 - self.factor
      
      ideal = soya.Point(self.target, 0.0, self.offset_y, self.distance)
      ideal_ratio = camera.distance_to(ideal) / self.distance
      
      self.target.move(self.character)
      
      _P.clone(self.enemy)
      _P.y = self.character.y
      self.target.look_at(_P)

      # Compute side
      _P.clone(camera)
      _P.convert_to(self.target)

      if self.changing_side == 0:
        if ideal_ratio > self.ideal_ratio > 0.5:
          if globdef.DEBUG: print "Change side !!!"
          if _P.x > 0.0: self.changing_side = -1
          else:          self.changing_side =  1
        self.ideal_ratio = ideal_ratio
        
      if   self.changing_side ==  1:
        self.target.rotate_lateral( 105.0)
        if ideal_ratio < 0.7:
          self.changing_side = 0;
          if globdef.DEBUG: print "done"
        
      elif self.changing_side == -1:
        self.target.rotate_lateral(-105.0)
        if ideal_ratio < 0.7:
          self.changing_side = 0;
          if globdef.DEBUG: print "done"
        
      elif _P.x > 0.0:               self.target.rotate_lateral( 105.0)
      else:                          self.target.rotate_lateral(-105.0)
      
      
      self.fight_target.set_xyz(
        self.factor * self.character.x + ff * self.enemy.x,
        self.character.y,
        self.factor * self.character.z + ff * self.enemy.z,
        )
      
      if self.next_enemy:
        if self.next_enemy == 1:
          if   self.offset_y2 < self.old_offset_y2: self.offset_y2 += 0.1
          elif self.offset_y2 > self.old_offset_y2: self.offset_y2 -= 0.1
          
        if self.factor < 1.0: self.factor += 0.01
        else:
          if self.next_enemy == 1: self._set_enemy(None)
          else:                    self._set_enemy(self.next_enemy)
          self.next_enemy = None
          
      else:
        if self.offset_y2 > 0.0: self.offset_y2 -= 0.1
        
        r = self.fight_target.distance_to(self.character) - 0.3 * self.fight_target.distance_to(camera)
        if   (r < -0.2) and (self.factor > 0.55): self.factor -= 0.01
        elif (r >  0.2) and (self.factor < 1.0 ): self.factor += 0.01
        
    r = soya.ThirdPersonTraveling.best_position(self, camera)
    
    for i in self.character.level.camera_can_pass_through: i.solid = 1
    
    return r

  def best_direction(self, camera):
    _V.set_start_end(camera, (self.fight_target or self.target))
    _V.y += self.offset_y + self.offset_y2
    return _V
  
  
  
class Traveling(soya.ThirdPersonTraveling):
  def __init__(self, character, *args):
    soya.ThirdPersonTraveling.__init__(self, character, *args)
    
    self.character      = character
    self.enemy          = None
    self.duration       = 0
    
    self.top_view       = 0.17
    self.distance       = 7.0
    self.offset_y       = 2.0
    self.offset_y2      = 1.0
    
  def is_in_fight_mode(self): return 0
  
  def set_enemy(self, enemy):
    if enemy:
      if self.character.distance_to(enemy) > 16.0: return
      
      _P.clone(enemy)
      _P.convert_to(tofu.GAME_INTERFACE.camera)
      
      if _P.x < 0.0: self.lateral_angle =  0.7
      else:          self.lateral_angle = -0.7
      
      self.duration = 100
      
    else: self.lateral_angle = 0.0
    
  def best_position(self, camera):
    if self.character.level:
      for i in self.character.level.camera_can_pass_through: i.solid = 0
      
    if self.duration:
      self.duration -= 1
      if self.duration == 0: self.set_enemy(None)

    r = soya.ThirdPersonTraveling.best_position(self, camera)
    
    if self.character.level:
      for i in self.character.level.camera_can_pass_through: i.solid = 1
      
    return r
