# Slune
# Copyright (C) 2002-2003 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

from __future__ import generators

import time, random, math

import soya
import py2play.level as py2p_level, py2play.action as action, py2play.character as character
import slune.character as slune_character
import slune.controler

CHROMOSOMS = {
  0: [0.9, 0.54152636319441949, 0.057433463934462713, 1.5669823329989161, 15.877046130951882, 0.18908021610553249, 0.066441050148349098, 3.0216818334258322, 0.1 ],
  1: [0.9, 0.54152636319441949, 0.057433463934462713, 1.5669823329989161, 15.877046130951882, 0.18908021610553249, 0.066441050148349098, 3.0216818334258322, 0.5],
  2: [0.9, 0.54152636319441949, 0.057433463934462713, 1.5669823329989161, 15.877046130951882, 0.18908021610553249, 0.066441050148349098, 3.0216818334258322, 1.0 ],
  }

class Praise(slune_character.NonPlayerCharacter):
  def __init__(self, parent = None, chromosom = None, path = (), escape_dist = 40.0, wait_dist = 10.0):
    slune_character.NonPlayerCharacter.__init__(self, parent)
    
    self.chromosom           = chromosom
    self.path                = path
    self.escape_dist         = escape_dist
    self.wait_dist           = wait_dist
    self.check_ground_vector = soya.Vector(self, 0.0, -1.5, -2.0)
    
  def finished(self): pass
  
  def escaped_from(self, hunter):
    import videosequence
    videosequence.HuntFailed().start(praise = self, hunter = hunter)
    
  def IAControler(character):
    c = character.chromosom = character.chromosom or CHROMOSOMS[character.level.difficulty]
    max_speed = c[8]
    jumping = 0
    
    mouse_x = mouse_y = 0.0
    
    while not character.path: yield slune_character.Action()
    
    while character.wait_dist:
      for hunter in character.level.characters:
        if isinstance(hunter, slune_character.Competitor):
          if character.distance_to(hunter) < character.wait_dist: character.wait_dist = 0.0
          yield slune_character.Action()
          
    while 1:
      if not character.path:
        while character.finished(): yield slune_character.Action(slune_character.ACTION_WAIT)
        while 1: yield slune_character.Action(slune_character.ACTION_WAIT)
        
      else:
        character.speed.y = 100.0 # Avoid null speed (null speed => jumping). The speed will be overrided later.
        
        next_flag = character.path.pop(0)
        
        if hasattr(next_flag, "next"): yield next_flag
        else:
          dist = 10.0
          while dist > 2.0:
            dist = character.distance_to(next_flag)
            for hunter in character.level.characters:
              if isinstance(hunter, slune_character.Competitor):
                if not(getattr(hunter, "failed", 0)) and (character.distance_to(hunter) > character.escape_dist):
                  hunter.failed = 1
                  character.escaped_from(hunter)
                  
            fx, fy, fz = character.transform_point(next_flag.x, next_flag.y, next_flag.z, next_flag.parent)
            
            if jumping:
              if character.on_ground: jumping = 0
              no_ground = 0 # It is normal that there is no ground !
            else:
              no_ground = not character.context.raypick_b(character, character.check_ground_vector, 4.0, 3)
              
            if ((dist < 12.0) and (c[5] * fy + c[6] * fz + c[7] * no_ground > 2.0)) or (character.speed.length() < 0.05):
              if character.random.random() < 0.7:
                action = slune_character.ACTION_JUMP
                jumping = 1
              else: yield slune.controler.Wall_climber(character)
            else:
              action = slune_character.ACTION_WAIT
              
            _mouse_x = min(1.0, -c[0] * math.sqrt(abs(fx / fz)))
            if fx > 0.0: _mouse_x = -_mouse_x
            mouse_x = 0.8 * mouse_x + 0.2 * _mouse_x
            mouse_y = (5.0 * mouse_y + min(max_speed, max(-max_speed, c[1] * abs(fx) + c[2] * fy + c[3] * fz + c[4] * no_ground))) / 6.0
            
            yield slune_character.Action(action, mouse_x, mouse_y)
            


class PathComputer:
  def __init__(self):
    self.pathes = {}
    
    
  def add_path(self, from_, to, path, reverse = 1):
    if self.pathes.has_key(from_):
      if self.pathes[from_].has_key(to):
        self.pathes[from_][to].append(path)
        
      else:
        self.pathes[from_][to] = [path]
        
    else:
      self.pathes[from_] = { to : [path] }
      
    if reverse:
      reverse_path = path[:]
      reverse_path.reverse()
      self.add_path(to, from_, reverse_path, 0)
      
  def random_path(self, start, end, approx_length, random = None):
    if not random: import random

    old_location = None
    location     = start
    
    path   = []
    length = 0
    while location != end:
      if length >= approx_length:
        if self.pathes[location].has_key(end):
          path.extend(random.choice(self.pathes[location][end]))
          #print "->", end
          
          break
        
      new_locations = self.pathes[location].keys()
      if (length < approx_length) and (len(new_locations) > 1):
        try: new_locations.remove(end)
        except: pass
        
      if len(new_locations) > 1:
        try: new_locations.remove(old_location)
        except: pass
        
      #print "choix parmi", new_locations
      
      old_location = location
      location     = random.choice(new_locations)
      path.extend(random.choice(self.pathes[old_location][location]))
      length += 1
      
      #print "->", location
      
    return path

  def path(self, *locations):
    path = []
    
    old_location = locations[0]
    for location in locations[1:]:
      path.extend(self.pathes[old_location][location][0])
      old_location = location
      
    return path
