# Balazar Brothers
# Copyright (C) 2006 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 random

import cerealizer, soya, tofu, soya.tofu4soya as tofu4soya
import soya.label3d

import balazar_brothers, balazar_brothers.globdef as globdef


class Platform(object):
  JUMP_SOUND = "jump1.wav"
  FALL_SOUND = "chute.wav"
  discussion = None
  
  def __init__(self):
    super(Platform, self).__init__()
    self.characters_on = []
    
  def suitable_for(self, character):
    if self.characters_on and not character.want_to_kill(self.characters_on[0]):
      return 0
    return 1
  
  def add_character(self, character, change_level = 0):
    if self.characters_on:
      if character.can_kill(self.characters_on[0]): self.characters_on[0].die(soya.Vector(character, 0.0, 0.0, -1.0))
      else: character.die(soya.Vector(character, 0.0, 0.0, 1.0)); return
      
    self.characters_on.append(character)
    
    from balazar_brothers.level import Level
    level = self.parent
    while not isinstance(level, Level): level = level.parent    
    character.move(self.platform_position % level)
    
    if character.level:
      if self.discussion and not character.bot: character.start_discussion(self.discussion)
    
  def remove_character(self, character):
    if character in self.characters_on: self.characters_on.remove(character)
    
  def radius(self, direction = None): return 0.0

  def is_next_for_character(self, character): pass
cerealizer.register(Platform)



class BasePlatform(Platform, tofu4soya.Mobile):
  def __init__(self):
    tofu4soya.Mobile.__init__(self)
    Platform.__init__(self)
    
    self.platform_position = self
    self.bot               = 1
cerealizer.register(BasePlatform)

class MultiCharactersPlatform(Platform):
  def __init__(self):
    super(MultiCharactersPlatform, self).__init__()
    
  def suitable_for(self, character): return 1
  
  def add_character(self, character, change_level = 0):
    self.characters_on.append(character)

    #if (not isinstance(self, StartingPlatform)) and (not isinstance(self, PortailPlatform)):
    #  if self.discussion and not character.bot: character.start_discussion(self.discussion)
    
    if character.level:
      if self.discussion and not character.bot: character.start_discussion(self.discussion)
cerealizer.register(MultiCharactersPlatform)
      
class BumpablePlatform(Platform):
  BUMP_SPEED   =  0.1
  UNBUMP_SPEED =  0.05
  MAX_BUMP     = -0.5
  def __init__(self):
    super(BumpablePlatform, self).__init__()
    
    self.bumped_y = 0.0
    
  def advance_time(self, proportion):
    super(BumpablePlatform, self).advance_time(proportion)
    if not self.characters_on:
      if self.bumped_y < 0.0:
        self.bumped_y += self.UNBUMP_SPEED * proportion
        self.y += self.UNBUMP_SPEED * proportion
    elif self.bumped_y > self.MAX_BUMP:
      self.bumped_y -= self.BUMP_SPEED * proportion
      self.y -= self.BUMP_SPEED * proportion
cerealizer.register(BumpablePlatform)

      
class AnimatedPlatform(Platform):
  def __init__(self):
    super(AnimatedPlatform, self).__init__()
    self.animated_volume = soya.Cal3dVolume(self)
    self.animated_volume.visible = 0
    self.animation_round = 0
    self.shape = soya.Shape.get(self.CHARACTER_OFF_SHAPE)
    
  def add_character(self, character, change_level = 0):
    if not self.characters_on:
      self.shape = None
      self.animated_volume.visible = 1
      self.animated_volume.animate_reset()
      self.animated_volume.animate_blend_cycle("character_on")
      self.animation_round = self.CHARACTER_ON_ANIMATION_ROUND
      
    super(AnimatedPlatform, self).add_character(character, change_level)
    
  def remove_character(self, character):
    super(AnimatedPlatform, self).remove_character(character)
    
    if not self.characters_on:
      self.shape = None
      self.animated_volume.visible = 1
      self.animated_volume.animate_reset()
      self.animated_volume.animate_blend_cycle("character_off")
      self.animation_round = self.CHARACTER_OFF_ANIMATION_ROUND
      
  def begin_round(self):
    super(AnimatedPlatform, self).begin_round()

    if self.animation_round:
      self.animation_round -= 1
      if self.animation_round == 0:
        if self.characters_on: self.shape = soya.Shape.get(self.CHARACTER_ON_SHAPE )
        else:                  self.shape = soya.Shape.get(self.CHARACTER_OFF_SHAPE)
        self.animated_volume.visible = 0
cerealizer.register(AnimatedPlatform)
        
        
class Coqueliform(BumpablePlatform, BasePlatform):
  def __init__(self):
    super(Coqueliform, self).__init__()
    self.shape = soya.Shape.get("coqueliforme")
cerealizer.register(Coqueliform)
    
    
class FallingCoqueliform(BumpablePlatform, BasePlatform):
  BUMP_SPEED   =  0.1
  UNBUMP_SPEED =  0.03
  MAX_BUMP     = -10.0
  
  def __init__(self):
    super(FallingCoqueliform, self).__init__()
    self.shape = soya.Shape.get("coqueliforme@bordeau")
cerealizer.register(FallingCoqueliform)
    

class RotatingCoqueliform(Coqueliform):
  def __init__(self):
    super(RotatingCoqueliform, self).__init__()
    self.shape = soya.Shape.get("coqueliforme@bleu")
    
  def advance_time(self, proportion):
    super(RotatingCoqueliform, self).advance_time(proportion)
    self.rotate_lateral(4.0 * proportion)
cerealizer.register(RotatingCoqueliform)


        
# class Mushroom(BumpablePlatform, BasePlatform):
#   static_model = "champignon@pos1"
#   CAL3D_model  = "champignon"
#   def __init__(self):
#     super(Mushroom, self).__init__()
#     self.shape = soya.Shape.get(self.static_model)
#     self.animated_volume = None
#     self.animation_round = 0
    
#   def begin_round(self):
#     super(Mushroom, self).begin_round()
    
#     if self.animation_round:
#       self.animation_round -= 1
#       if self.animation_round == 0:
#         self.shape = soya.Shape.get(self.static_model)
#         self.remove(self.animated_volume)
#         self.animated_volume = None
        
#     elif not self.characters_on:
#       if random.random() < 0.01:
#         self.shape = None
#         self.animated_volume = soya.Cal3dVolume(self, soya.Cal3dShape.get(self.CAL3D_model))
#         self.animated_volume.animate_blend_cycle("character_on")
#         self.animation_round = 23

class Mushroom(BumpablePlatform, BasePlatform):
  def __init__(self):
    super(Mushroom, self).__init__()
    self.shape = soya.Shape.get("champignon@pos1")
cerealizer.register(Mushroom)

class RotatingMushroom(Mushroom):
  def __init__(self):
    super(RotatingMushroom, self).__init__()
    self.shape = soya.Shape.get("champignon@bleupos1")
    
  def advance_time(self, proportion):
    super(RotatingMushroom, self).advance_time(proportion)
    self.rotate_lateral(3.0 * proportion)
cerealizer.register(RotatingMushroom)
    

class Fasme(BumpablePlatform, BasePlatform):
  def __init__(self):
    super(Fasme, self).__init__()
    self.shape = soya.Shape.get("fasme@pos1")
cerealizer.register(Fasme)

class RotatingFasme(Fasme):
  def __init__(self):
    super(RotatingFasme, self).__init__()
    self.shape = soya.Shape.get("fasme@bleupos1")
    
  def advance_time(self, proportion):
    super(RotatingFasme, self).advance_time(proportion)
    self.rotate_lateral(3.0 * proportion)
cerealizer.register(RotatingFasme)
    
class UpDownFasme(Fasme):
  def __init__(self):
    super(Fasme, self).__init__()
    self.shape  = None
    self.volume = soya.Cal3dVolume(self, soya.Cal3dShape.get("fasme"))
    self.attached_world = soya.World(self)
    self.platform_position = soya.Point(self.attached_world, 0.0, 0.3, 0.0)
    self.volume.attach_to_bone(self.attached_world, "Bone_005")
    self.pos = 0
    
    self.volume.animate_blend_cycle("haut")
    self.volume.begin_round()
    self.volume.advance_time(0.1)
    
  def begin_round(self):
    Fasme.begin_round(self)
    self.pos += 1
    if self.pos == 30:
      self.volume.animate_clear_cycle("bas", 0.4)
      self.volume.animate_blend_cycle("haut")
    if self.pos == 60:
      self.volume.animate_clear_cycle("haut", 0.4)
      self.volume.animate_blend_cycle("bas")
      self.pos = 0
cerealizer.register(UpDownFasme)
      
class Fountain(BasePlatform):
  def __init__(self):
    super(Fountain, self).__init__()
    self.shape = soya.Shape.get("fontaine")
    self.water = soya.Volume(self, soya.Shape.get("fontaine_eau"))
    
  def advance_time(self, proportion):
    super(Fountain, self).advance_time(proportion)
    
    if self.characters_on and self.water.y > -3.0 :
      self.water.y -= proportion * 0.5
      
    elif (not self.characters_on) and self.water.y < 0.0 :
      self.water.y += proportion * 0.1
cerealizer.register(Fountain)
    
# import soya.spc_material
# m = soya.spc_material.MovingMaterial(soya.Image.get("fontaine_eau.png"), 0.0, -0.03)
# m.additive_blending = 1
# m.filename = "fontaine_eau"
# m.save()

# w = soya.World.get("fontaine_eau")
# for f in w:
#   print f
#   f.lit = 1
#   for p in f:
#     if p.z < -2.0:
#       print p
#       p.color = (0.0, 0.0, 0.0, 1.0)
#       #p.color = (1.0, 1.0, 1.0, 0.0)
# w.save()

#import soya.spc_material
#m = soya.spc_material.ZoomingMaterial(soya.Image.get("portail.png"), 0.2, 0.2)
#m.additive_blending = 1
#m.filename = "portail"
#m.save()

P1 = soya.Point()

class StartingPlatform(MultiCharactersPlatform, BasePlatform):
  def __init__(self):
    super(StartingPlatform, self).__init__()
    self.shape = soya.Shape.get("plateforme")
    
  def add_character(self, character, change_level = 0):
    super(StartingPlatform, self).add_character(character)
    
    if   len(self.characters_on) == 1: P1.__init__(self, -1.0, 0.0, 0.0)
    elif len(self.characters_on) == 2: P1.__init__(self,  1.0, 0.0, 0.0)
    elif len(self.characters_on) == 3: P1.__init__(self, -0.5, 0.0, 0.0)
    elif len(self.characters_on) == 4: P1.__init__(self,  0.5, 0.0, 0.0)
    P1.convert_to(self.parent)
    character.move(P1)
cerealizer.register(StartingPlatform)
    

class PortailPlatform(MultiCharactersPlatform, BasePlatform):
  FALL_SOUND = "menu2.wav"
  
  def __init__(self, next_level_name = ""):
    super(PortailPlatform, self).__init__()
    
    self.next_level_name = next_level_name
    self.shape = soya.Shape.get("plateforme-1")
    
    self.label = Label3D(self, "Label")
    self.label.y = 7.5
    self.label.size = 0.03
    self.label.lit = 0
    self.label.center_y = 1
    
  def add_character(self, character, change_level = 1):
    from balazar_brothers.character import Balazar
    from balazar_brothers.player    import Player
    
    if not isinstance(character, Balazar): change_level = 0
    
    if change_level:
      if self.doer.remote: return
      else:
        from balazar_brothers.level import Level
        if self.next_level_name in Level.availables():
          next_level = Level.get(self.next_level_name)
          
          player = Player.get(character.player_name)
          player.current_level_name  = self.next_level_name
          player.previous_level_name = character.level.filename
          
          for c in character.level.mobiles[:]:
            if c.player_name == character.player_name:
              c.previous_level_name = c.level.filename
              if c.platform:
                c.platform.remove_character(c)
                c.platform      = None
                c.next_platform = None
              c.level.remove_mobile(c)
              next_level.add_mobile(c)
              
          return
        
    super(PortailPlatform, self).add_character(character)
    
    if   len(self.characters_on) == 1: P1.__init__(self, -1.0, 0.0, 0.0)
    elif len(self.characters_on) == 2: P1.__init__(self,  1.0, 0.0, 0.0)
    elif len(self.characters_on) == 3: P1.__init__(self, -0.5, 0.0, 0.0)
    elif len(self.characters_on) == 4: P1.__init__(self,  0.5, 0.0, 0.0)
    P1.convert_to(self.parent)
    character.move(P1)
cerealizer.register(PortailPlatform)
    

class Label3D(soya.label3d.Label3D):
  _font = None
  def __init__(self, parent = None, text = "", font = None, size = 0.01):
    soya.label3d.Label3D.__init__(self, parent, text, font, size)
    
    del self._font

  def loaded(self):
    from balazar_brothers.level import level_display_name
    
    if self.parent.parent.get_country_name() == self.parent.next_level_name[:self.parent.next_level_name.rfind("_")]:
      self.text = self.parent.next_level_name[self.parent.next_level_name.rfind("_") + 1:]
      self.size = 0.07
    else:
      self.text = _(u"Towards %s") % level_display_name(self.parent.next_level_name)
      self.size = 0.03
      
    if globdef.mode != "--level-editor":
      from balazar_brothers.level import Level
      if not self.parent.next_level_name in Level.availables():
        self.text = _("__unavailable_level__")
cerealizer.register(Label3D)


class OpenState(tofu4soya.State):
  def __init__(self, mobile):
    tofu4soya.State.__init__(self)
cerealizer.register(OpenState)
    
class CloseState(tofu4soya.State):
  def __init__(self, mobile):
    tofu4soya.State.__init__(self)
cerealizer.register(CloseState)
    
    
    
class Openable(object):
  OPEN_SOUND  = ""
  CLOSE_SOUND = ""
  SOUND_GAIN = 1.0
  
  def __init__(self):
    super(Openable, self).__init__()
    
    self.opened             = 0
    self.close_duration     = 0
    self.autoclose_duration = 0
    
  def big_round(self):
    if not self.doer.remote:
      if self.opened and self.close_duration:
        self.close_duration -= 1
        if self.close_duration == 0: self.set_opened(0)
        
  def set_opened(self, opened):
    if opened != self.opened:
      if opened:
        self.doer.action_done(OpenState(self))
        self.close_duration = self.autoclose_duration
      else:
        self.doer.action_done(CloseState(self))
        
  def set_state(self, state):
    if   isinstance(state, OpenState):
      if not self.opened:
        if self.OPEN_SOUND: balazar_brothers.sound.play(self.OPEN_SOUND, self, gain = self.SOUND_GAIN)
        self.opened = 1
        
    elif isinstance(state, CloseState):
      if self.opened:
        if self.CLOSE_SOUND: balazar_brothers.sound.play(self.CLOSE_SOUND, self, gain = self.SOUND_GAIN)
        self.opened = 0
cerealizer.register(Openable)
        
        
class Door(Openable, BasePlatform):
  OPEN_SOUND = "door_open.wav"
  SOUND_GAIN = 10.0
  def __init__(self):
    super(Door, self).__init__()
    self.shape = soya.Shape.get("portique1")
    
    self.door1 = soya.Volume(self, soya.Shape.get("porte"))
    self.door1.set_xyz(-1.0, 0.0, 0.72)
    
    self.door2 = soya.Volume(self, soya.Shape.get("porte_m"))
    self.door2.set_xyz( 1.0, 0.0, 0.72)
    #self.door2.scale(-1.0, 1.0, 1.0)
    
    self.rotation = 0.0
    
  def suitable_for(self, character):
    return  super(Door, self).suitable_for(character) and (self.opened or character.keys >= 7)
  
  def is_next_for_character(self, character):
    if not self.opened:
      if character.keys >= 7:
        if not self.doer.remote:
          tofu.Player.get(character.player_name).add_bonus(keys = -7)
          self.set_opened(1)
          
        return 1
    return 0
  
  def advance_time(self, proportion):
    if       self.opened and self.rotation < 150.0:
      self.rotation += 3 * proportion
      self.door1.rotate_lateral(-3 * proportion)
      self.door2.rotate_lateral( 3 * proportion)
      
    elif not self.opened and self.rotation >   0.0:
      self.rotation -= 3 * proportion
      self.door1.rotate_lateral( 3 * proportion)
      self.door2.rotate_lateral(-3 * proportion)
cerealizer.register(Door)


class TreePompon(soya.Volume):
  def __init__(self, parent = None):
    soya.Volume.__init__(self, parent, soya.Shape.get("scn-tree5"))
cerealizer.register(TreePompon)
  
class Farm(soya.World):
  def __init__(self, parent = None):
    soya.World.__init__(self, parent, soya.Shape.get("ferme_champignon"))
    self.farm = soya.Volume(self, soya.Shape.get("ferme"))
cerealizer.register(Farm)
