# 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, soya.widget as widget, soya.ray as ray
import py2play.level as py2p_level, py2play.action as action, py2play.character as character
from soya import Point, Vector
import slune.character as slune_character, slune.globdef as globdef
import slune.controler


def init_fight_game(level):
  pass

def start_fight_game(level):
  CheckEveryoneIsKilled(level)
  
def end_fight_game(level):
  pass

class CheckEveryoneIsKilled(soya.Volume):
  def begin_round(self):
    from py2play.player import CURRENT_PLAYER
    
    if (len(self.parent.characters) == 1) and (self.parent.characters[0] is CURRENT_PLAYER.character):
      from py2play.idler import IDLER
      
      IDLER.level_completed(CURRENT_PLAYER.character, 1)
      
      self.parent.remove(self)
      

STRATEGY_RUN      = 0
STRATEGY_FLEE     = 1
STRATEGY_BACKSTAB = 2
STRATEGY_DODGE    = 3
STRATEGY_FRONTRUN = 4
STRATEGY_SIDERUN  = 5
STRATEGY_WANDER   = 6

class FightChromosom:
  def __init__(self, max_speed, will, turbosity, autododge, run, dodge, flee, frontrun, siderun, wander):
    self.max_speed   = max_speed
    self.will        = will
    self.turbosity   = turbosity
    self.autododge   = autododge
    self.run         = run
    self.dodge       = dodge
    self.flee        = flee
    self.frontrun    = frontrun
    self.siderun     = siderun
    self.wander      = wander
    
  def mutate(self, random):
    for attr, value in self.__dict__.iteritems():
      if attr != "max_speed":
        if random.random() < 0.4: 
          setattr(self, attr, value * (0.5 + random.random()))
          
CHROMOSOMS = {
  
  ("tux", 0):    FightChromosom(0.65, 100.0, -7.0, 0.0, 0.8, 1.0, 0.1, 1.7, 1.0, 1.3),
  ("tux", 1):    FightChromosom(0.8,  100.0, -1.0, 0.0, 1.0, 1.1, 0.6, 1.1, 1.3, 1.0),
  ("tux", 2):    FightChromosom(0.9,  100.0,  0.5, 2.5, 1.0, 1.5, 1.1, 1.0, 1.5, 0.5),
  
  ("gnu", 0):    FightChromosom(0.6,  150.0, -2.0, 0.0, 1.2, 1.0, 0.1, 2.0, 0.6, 1.5),
  ("gnu", 1):    FightChromosom(0.75, 150.0,  0.7, 0.0, 1.8, 0.6, 0.3, 1.2, 0.7, 1.1),
  ("gnu", 2):    FightChromosom(0.9,  150.0,  1.0, 1.5, 2.0, 0.5, 0.4, 0.5, 1.0, 0.5),
  
  ("shark", 0):  FightChromosom(0.6,   80.0, -9.0, 0.0, 0.9, 1.0, 0.2, 1.6, 0.5, 1.5),
  ("shark", 1):  FightChromosom(0.7,   80.0, -4.0, 1.0, 1.0, 1.4, 0.5, 1.0, 0.5, 1.2),
  ("shark", 2):  FightChromosom(0.9,   70.0,  0.0, 1.5, 1.0, 1.5, 0.6, 0.2, 0.5, 0.9),

  ("python", 0): FightChromosom(0.6,  100.0,  0.0, 0.0, 1.2, 1.0, 0.1, 2.0, 0.6, 1.5),
  ("python", 1): FightChromosom(0.8,  100.0,  1.3, 0.5, 1.8, 0.6, 0.3, 1.2, 0.7, 1.1),
  ("python", 2): FightChromosom(0.9,  100.0,  2.0, 2.5, 2.0, 0.5, 0.4, 0.5, 1.0, 0.5),
  
  
#   ("tux", 0): [0.23161940934461928, 0.0, 0.0, 0.54152636319441949, 0.057433463934462713, 1.5669823329989161, 15.877046130951882, 0.18908021610553249, 0.066441050148349098, 3.0216818334258322, 2.0, 0.0, 0.8, 1.0, 0.1, 1.7, 1.0, 1.3, 0.65, 20.0],
#   ("tux", 1): [0.23161940934461928, 0.0, 0.0, 0.54152636319441949, 0.057433463934462713, 1.5669823329989161, 15.877046130951882, 0.18908021610553249, 0.066441050148349098, 3.0216818334258322, 3.0, 0.0, 1.0, 1.1, 0.6, 1.1, 1.3, 1.0, 0.8 , 10.0],
#   ("tux", 2): [0.23161940934461928, 0.0, 0.0, 0.54152636319441949, 0.057433463934462713, 1.5669823329989161, 15.877046130951882, 0.18908021610553249, 0.066441050148349098, 3.0216818334258322, 4.0, 2.5, 1.0, 1.5, 1.1, 1.0, 1.5, 0.5, 0.9 ,  1.0],
  
#   ("gnu", 0): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 2.0, 0.0, 1.2, 1.0, 0.1, 2.0, 0.6, 1.5, 0.6 , 30.0],
#   ("gnu", 1): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 3.0, 0.0, 1.8, 0.6, 0.3, 1.2, 0.7, 1.1, 0.75, 20.0],
#   ("gnu", 2): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 3.5, 1.5, 2.0, 0.5, 0.4, 0.5, 1.0, 0.5, 0.9 , 3.0],
  
#   ("shark", 0): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 2.0, 0.0, 0.9, 1.0, 0.2, 1.6, 0.5, 1.5, 0.6, 20.0],
#   ("shark", 1): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 3.0, 1.0, 1.0, 1.4, 0.5, 1.0, 0.5, 1.2, 0.7, 12.0],
#   ("shark", 2): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 3.5, 1.5, 1.0, 1.5, 0.6, 0.2, 0.5, 0.9, 0.9,  2.0],

# For mission levels
#  ("killer", 0): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 2.0, 0.0, 1.2, 0.0, 0.0, 0.0, 0.6, 0.5, 0.85, 1.0],
#  ("killer", 1): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 3.0, 0.0, 1.8, 0.0, 0.0, 0.0, 0.7, 0.2, 0.92,  1.0],
#  ("killer", 2): [0.27955060118474129, 0.0, 0.0, 0.94713263528551006, 0.0076398049940541654, 0.46242007806615826, 22.758284696585228, 0.07628649333395944, 0.0051247277708940846, 5.6391784712330182, 3.5, 0.0, 2.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.05,  1.0],
  
  ("killer", 0):    FightChromosom(0.6,  150.0, 0.2, 0.0, 1.2, 1.0, 0.1, 2.0, 0.6, 1.5),
  ("killer", 1):    FightChromosom(0.75, 150.0, 0.7, 0.0, 1.8, 0.6, 0.3, 1.2, 0.7, 1.1),
  ("killer", 2):    FightChromosom(0.9,  150.0, 1.0, 1.5, 2.0, 0.5, 0.4, 0.5, 1.0, 0.5),
  
  ("killer_flight", 0): FightChromosom(0.6,  150.0, -10.0, 0.0, 1.2, 1.0, 0.1, 2.0, 0.6, 1.5),
  ("killer_flight", 1): FightChromosom(0.75, 150.0, -10.0, 0.0, 1.8, 0.6, 0.3, 1.2, 0.7, 1.1),
  ("killer_flight", 2): FightChromosom(0.9,  150.0, -10.0, 1.5, 2.0, 0.5, 0.4, 0.5, 1.0, 0.5),
  
  ("alien_boss", 0):    FightChromosom(0.9, 150.0, 1.5, 1.5, 2.0, 0.5, 0.4, 0.5, 1.0, 0.5),
  ("alien_boss", 1):    FightChromosom(0.9, 150.0, 1.0, 0.0, 1.8, 0.6, 0.3, 1.2, 0.7, 1.1),
  ("alien_boss", 2):    FightChromosom(0.9, 150.0, 0.7, 0.0, 1.2, 1.0, 0.1, 2.0, 0.6, 1.5),
  }

class Fighter(slune_character.NonPlayerCharacter):
  def __init__(self, parent = None, chromosom = None):
    slune_character.NonPlayerCharacter.__init__(self, parent)
    
    self.chromosom = chromosom
    self.clan = 2
    
  def choose_target(self):
    best      = None
    best_dist = 10000.0
    for level in self.get_root():
      if isinstance(level, py2p_level.Level):
        for character in level.characters:
          if (not character is self) and (character.clan > 0) and (character.clan != self.clan):
            dist = character.distance_to(self)
            if dist < best_dist:
              best      = character
              best_dist = dist
    return best
  
  def choose_strategy(self, target):
    dist = self.distance_to(target)
    c = self.chromosom
    return max(
      (self.life              + self.random.random() * c.run,      STRATEGY_RUN),
      (self.life - 0.1 * dist + self.random.random() * c.dodge,    STRATEGY_DODGE),
      (1.0 - 2.0 * self.life  + self.random.random() * c.flee,     STRATEGY_FLEE),
      (self.life              + self.random.random() * c.frontrun, STRATEGY_FRONTRUN),
      (self.life              + self.random.random() * c.siderun,  STRATEGY_SIDERUN),
      (                         self.random.random() * c.wander,   STRATEGY_WANDER),
      )[1]
  
  def init(self):
    if not self.perso_name:
      persos = list(globdef.CHARACTERS)
      self.random.shuffle(persos)
      for perso in persos:
        perso = perso.lower()
        for c in self.level:
          if (hasattr(c, "perso_name")) and (c.perso_name == perso): break
        else:
          self.perso_name = perso
          break
      else: self.perso_name = persos[0].lower()
    self.set_perso(self.perso_name)
    self.set_vehicle(self.random.choice(globdef.VEHICLES.values()))
    
  def IAControler(self):
    c = self.chromosom = self.chromosom or CHROMOSOMS[self.perso_name, self.level.difficulty]
    c.mutate(self.random)
    self.max_speed = c.max_speed
    
    target = None
    while 1:
      target   = self.choose_target() or target
      strategy = self.choose_strategy(target)
      
      if   strategy == STRATEGY_RUN:
        yield slune.controler.AttackRun(self, target, c.will, c.autododge, c.turbosity + 2.0 * self.life)
        
      elif strategy == STRATEGY_FRONTRUN:
        yield slune.controler.AttackFrontRun(self, target, c.will, c.autododge, c.turbosity + 2.0 * self.life)
        
      elif strategy == STRATEGY_SIDERUN:
        yield slune.controler.AttackSideRun(self, target, c.will, c.autododge, c.turbosity + 2.0 * self.life)
        
      elif strategy == STRATEGY_FLEE:
        yield slune.controler.Flee(self, target, c.will)
        
      elif strategy == STRATEGY_DODGE:
        yield slune.controler.Feinte(self, target, c.will, c.autododge + 3.0)
        
      elif strategy == STRATEGY_WANDER:
        yield slune.controler.Wander(self, c.will)

        
class AlienBoss(Fighter, slune_character.Competitor):
  def __init__(self, parent = None):
    from py2play.player import CURRENT_PLAYER
    Fighter.__init__(self, parent, CHROMOSOMS["alien_boss", CURRENT_PLAYER.level.difficulty])


class Mission6Killer(slune_character.NonPlayerCharacter):
  def __init__(self, parent = None, chromosom = None):
    slune_character.NonPlayerCharacter.__init__(self, parent)
    
    self.chromosom = chromosom
    self.clan = 2
    
  def choose_target(self):
    best      = None
    best_dist = 10000.0
    for level in self.get_root():
      if isinstance(level, py2p_level.Level):
        for character in level.characters:
          if (not character is self) and (character.clan > 0) and (character.clan != self.clan):
            dist = character.distance_to(self)
            if dist < best_dist:
              best      = character
              best_dist = dist
    return best
  
  def init(self):
    self.set_perso(self.perso_name)
    
  def IAControler(self):
    c = self.chromosom = self.chromosom or CHROMOSOMS[self.perso_name, self.level.difficulty]
    self.max_speed = c.max_speed
    
    from py2play.idler import IDLER
    
    while 1:
      target = self.choose_target() or target
      if not hasattr(target, "nb_avertissements"):
        target.disabled          = 0
        target.nb_avertissements = {0:4, 1:2, 2:0}[target.level.difficulty]
        
      for i in range(100):
        fx, fy, fz = self.transform_point(target.x, target.y, target.z, target.parent)
        
        if   target.disabled: target.disabled -= 1
        elif (target.y < 1.4) and (fz < 0.0) and (self.distance_to(target) < 3.0):
          IDLER.message(_("__scenar6-1__"))
          if target.nb_avertissements:
            target.disabled = 100
            target.nb_avertissements -= 1
          else: # You loose...
            from videosequence import GnuSpeech
            GnuSpeech((_("__scenar6-2__"), _("__gameover__")), 1).start(tux = target)
            
            while 1: yield slune_character.Action()
            
        yield slune.controler.runto(self, target, canjump = 0)
        

class Mission7Pusher(slune_character.NonPlayerCharacter):
  def __init__(self, parent = None, chromosom = None):
    slune_character.NonPlayerCharacter.__init__(self, parent)
    
    self.chromosom = chromosom
    
    self.clan = 2
    self.check_ground_vector = Vector(self, 0.0, -2.0, -2.0)
    self.jumping = 0
    self.current_action = slune_character.Action()
    
  def choose_target(self):
    best      = None
    best_dist = 10000.0
    for level in self.get_root():
      if isinstance(level, py2p_level.Level):
        for character in level.characters:
          if (not character is self) and (character.clan > 0) and (character.clan != self.clan):
            dist = character.distance_to(self)
            if dist < best_dist:
              best      = character
              best_dist = dist
    return best
  
  def init(self): self.set_perso(self.perso_name)
  
  def IAControler(self):
    c = self.chromosom = self.chromosom or CHROMOSOMS[self.perso_name, self.level.difficulty]
    self.max_speed = c.max_speed
    
    from py2play.idler import IDLER
    
    for i in range([10000, 10, 6][self.parent.difficulty]):
      target = self.choose_target() or target
      yield slune.controler.PushToKill(self, target, c.turbosity + 2.0 * self.life)
      
    while 1: # Turn berserk
      target = self.choose_target() or target
      yield slune.controler.AttackRun(self, target, turbosity = c.turbosity + 2.0 * self.life)
      

