------ All content © 2008 DigiPen (USA) Corporation, all rights reserved. ------
-- Author: Hamza M. Hutchinson
-- Updated: 04/03/2008

dofile( "../../Assets/Scripts/util_math.lua" )


--------------------------------------------------------------------------------
-- Fuctions!
-- This might look redundant, but avoids costly global lookup
--------------------------------------------------------------------------------

local ENTITY = Entity

local MATH_sqrt                      = math.sqrt

local GLOBAL_CreateEntity            = Global.CreateEntity
local GLOBAL_CreateEntityAt          = Global.CreateEntityAt
local GLOBAL_SetCameraUpVector       = Global.SetCameraUpVector
local GLOBAL_DockingProcedure        = Global.DockingProcedure
local GLOBAL_gVineEndPoint           = Global.gVineEndPoint
local GLOBAL_GrowVine                = Global.GrowVine
local GLOBAL_sVineGrowSpeed          = Global.sVineGrowSpeed
local GLOBAL_gVineGrowSpeed          = Global.gVineGrowSpeed
local GLOBAL_EmbiggenVine            = Global.EmbiggenVine
local GLOBAL_MusicLayer              = Global.MusicLayer
local GLOBAL_TimeElapsed             = Global.TimeElapsed
local GLOBAL_FireflySpawnMsg         = Global.FireflySpawnMsg
local GLOBAL_gRangeState             = Global.gRangeState
local GLOBAL_gLanternsCollected      = Global.gLanternsCollected

local ENTITY_SHR_gPosition           = Entity.SHR_gPosition
local ENTITY_SHR_gVelocity           = Entity.SHR_gVelocity
local ENTITY_SHR_sPosition           = Entity.SHR_sPosition
local ENTITY_SHR_sVelocity           = Entity.SHR_sVelocity
local ENTITY_SHR_sScale              = Entity.SHR_sScale
local ENTITY_SPT_GiveNumber          = Entity.SPT_GiveNumber
local ENTITY_SPT_RefreshNumbers      = Entity.SPT_RefreshNumbers

local ENTITY_PHY_SetAccel            = Entity.PHY_SetAccel


--------------------------------------------------------------------------------
-- Vars
--------------------------------------------------------------------------------

--moon size and junk
local JUST_STARTED = { started1 = nil }
local RADIUS            = 510
local ATMOSPHERE        = 10
local DENOM             = 1000
local MIN_SCALE
local MAX_SCALE
local MIN_RADIUS
local FRICTION             = .95
local FORCEDSEQUENCE_START = 300
local PLAYER_TOO_CLOSE     = 500
local FORCEDSEQUENCE_SPEED = 5
local ENDSEQUENCE_START = 120

--player position junk
local myData    = {}
local LANTERN   = Player:gLantern()
local ASTER     = Player:gAster()
local AsterPos  = ENTITY_SHR_gPosition( ASTER )
local AsterVel  = ENTITY_SHR_gVelocity( ASTER )
local pos       = ENTITY_SHR_gPosition( ENTITY )
local rod       = Global:FindEntityByName( "rod03", false )

--vine docking junk
local finished         = false
local collidedWithVine = false
local guidingVine      = false
local embiggeningVine  = true
local vineID           = -1

--end sequence junk
local endSequence = nil
local forcedTimer = 0
local FORCEDTEXT1 = 18
local FORCEDTIMER = 57
local forcedForever = {}
local FrameCount = 30
local FRAMECOUNT = 20
local FRAMECOUNTINC = 10
local MAXFRAMECOUNT = 120

local heightCheck1 = false
local heightCheck2 = false
local closeEnough = false


--------------------------------------------------------------------------------
-- Add popup text
--------------------------------------------------------------------------------

local function AddText( text, y )
  local len = string.len( text )

  local CHAR_WIDTH = ( 0.6 / 40.0 ) * len
  local CHAR_TIME = 175

  Global:AddPopupTextToQueue( text, CHAR_TIME * len, ( 1 - CHAR_WIDTH ) / 2, y )

end


--------------------------------------------------------------------------------
-- Clamp function
--------------------------------------------------------------------------------

local function Clamp( val, min, max )
  if( val < min ) then
    return min
    
  end

  if( val > max ) then
    return max
    
  end

  return val
end


--------------------------------------------------------------------------------
-- Loop
--------------------------------------------------------------------------------

if( rod ~= nil )
then
  MIN_SCALE = .14
  MAX_SCALE = 1.5
  
  local pillarPos = ENTITY_SHR_gPosition( rod )
  local pillarOff = vec3.normalize( vec3.subtract( pos, pillarPos ) )

  pillarOffFull = vec3.multiply( pillarOff, ( RADIUS * 3 ) * MAX_SCALE )
  pos = vec3.add( pillarPos, pillarOffFull )
  ENTITY_SHR_sPosition( ENTITY, pos.x, pillarPos.y - 100, pos.z )
  
else
  MIN_SCALE = 1
  MAX_SCALE = 1

end
MIN_RADIUS = MIN_SCALE * RADIUS
  
  
while( 1 ) 
do
  coroutine.yield()
  
  ENTITY = Entity

  ENTITY_SPT_RefreshNumbers( ENTITY, myData )
  
  ------------------------------------------------------------------------------
  -- check to get our numbers just once
  ------------------------------------------------------------------------------
  
  if( not JUST_STARTED.started1 )
  then
    ENTITY_SPT_RefreshNumbers( ENTITY, myData )
    JUST_STARTED.started1 = myData.started1
    
  end

  AsterPos = ENTITY_SHR_gPosition( ASTER )
  VinePos  = GLOBAL_gVineEndPoint()
  pos      = ENTITY_SHR_gPosition( ENTITY )
  
  ------------------------------------------------------------------------------
  -- don't let the player fly toward us aimlessly in the first area
  ------------------------------------------------------------------------------
  
  if( not heightCheck1 ) and ( Global:CurrArea() == 1 ) and ( AsterPos.y >= 525 ) 
  then
    heightCheck1 = true
    Global:CreateEntity( "../../Assets/Xml/entities/game_MidSequence.xml" )
    
  end
  if( not heightCheck2 ) and ( Global:CurrArea() == 2 ) and ( AsterPos.y >= 700 ) 
  then
    heightCheck2 = true
    JUST_STARTED.started1 = 1
    
  end
  
    
  ------------------------------------------------------------------------------
  -- scale the size of the moon
  ------------------------------------------------------------------------------
  
  local x = VinePos.x - pos.x
  local y = VinePos.y - pos.y
  local z = VinePos.z - pos.z

  local dist  = MATH_sqrt(x * x + y * y + z * z)
  local scale = Clamp( dist / DENOM, MIN_SCALE, MAX_SCALE )

  ENTITY_SHR_sScale( ENTITY, scale, scale, scale )
  
  x = AsterPos.x - pos.x
  y = AsterPos.y - pos.y
  z = AsterPos.z - pos.z

  dist  = MATH_sqrt(x * x + y * y + z * z)
  scale = Clamp( dist / DENOM, MIN_SCALE, MAX_SCALE )
  
  
  ------------------------------------------------------------------------------
  -- forced direction
  ------------------------------------------------------------------------------
  
  local toMoon = vec3.construct( pos.x - AsterPos.x, pos.y - AsterPos.y, pos.z - AsterPos.z )
  toMoon = vec3.normalize( toMoon )
  
  ----------------------------------------------------------------------------
  -- forced journey hasn't started, so direct the player away from the moon
  if( not JUST_STARTED.started1 )
  then
    if( dist < PLAYER_TOO_CLOSE )
    then
      if( not closeEnough )
      then
        AddText( "Climb above the moon to end the dream", .8 )
      end
      toMoon = vec3.negate( toMoon )
      GLOBAL_GrowVine( toMoon.x, toMoon.y, toMoon.z )
      GLOBAL_sVineGrowSpeed( FORCEDSEQUENCE_SPEED )
      closeEnough = true
    else
      closeEnough = false
    
    end
    
  end
  
  ------------------------------------------------------------------------------
  -- not to the credits yet
  if( endSequence == nil and rod ~= nil )
  then
  
    ----------------------------------------------------------------------------
    -- position the moon according to scale
    if( not JUST_STARTED.started1 or JUST_STARTED.started1 < 3 )
    then
      pillarPos = ENTITY_SHR_gPosition( Global:FindEntityByName( "rod03", false ) )
      pillarOff = vec3.normalize( vec3.subtract( pos, pillarPos ) )

      local p = vec3.add( pillarPos, pillarOffFull )
      ENTITY_SHR_sPosition( ENTITY, p.x, pillarPos.y - 100, p.z )
      
    end
    
    if( JUST_STARTED.started1 )
    then
      --------------------------------------------------------------------------
      -- forced journey has begun; let people know
      if( JUST_STARTED.started1 == 1 )
      then
        Global:AreaMsg( 3 )
        ENTITY_SPT_GiveNumber( LANTERN, "forcedSequence", 1 )
        ENTITY_SPT_GiveNumber( ASTER, "forcedSequence", 1 )
        JUST_STARTED.started1 = 2
        
      --------------------------------------------------------------------------
      -- time the journey to coincide with the music
      elseif( JUST_STARTED.started1 > 1 )
      then
        forcedTimer = forcedTimer + ( Global:TimeElapsed() / 1000 )

        -- Cheesey added steering for the player
        local range = GLOBAL_gRangeState( 0 )
        local up = { x = 0, y = 1, z = 0 }
        local side = vec3.cross( toMoon, up )
        vec3.multiplyThis( side, range.x * .1 )
        toMoon = vec3.add( toMoon, side )

        -- Growing
        Global:DockingProcedure( toMoon.x, toMoon.y, toMoon.z )
        GLOBAL_sVineGrowSpeed( FORCEDSEQUENCE_SPEED )
                    
        ------------------------------------------------------------------------
        -- moon-centric popup text
        if( forcedTimer >= FORCEDTEXT1 ) 
        then
          local lanternCount = GLOBAL_gLanternsCollected()
          AddText( "A maroon ... at journey's end ...", .8 )
          if( lanternCount > 18 )
          then
            AddText( "Dreaming ... to push back the dawn ...", .8 )   --keeping the dream alive cause you rock
            AddText( "A peaceful trip through the seasons", .8 )
          elseif( lanternCount > 9 )
          then
            AddText( "Dreaming ... in the darkest of night ...", .8 ) --partly into the night cause you suck less
            AddText( "A dream with all the beauty of fall", .8 )
          elseif( lanternCount > 1 )
          then
            AddText( "The night closes, yet to be fully realized ...", .8 )      --still early cause you suck
            AddText( "The lazy summer passing like a dream", .8 )
          else
            AddText( "You can light more lanterns next time ... maybe", .8 )      --still early cause you suck
            AddText( "That's kinda the point", .8 )
          end

          FORCEDTEXT1 = 100 -- hack
          
        end
                    
        ------------------------------------------------------------------------
        -- song is over; start credits
        if( forcedTimer >= FORCEDTIMER ) 
        then
          Global:AreaMsg( 4 )
          endSequence = GLOBAL_CreateEntity( "../../Assets/Xml/entities/game_EndSequence.xml" )
          Global:Dock( )
          MIN_RADIUS = scale * RADIUS
          
        end
        
        ------------------------------------------------------------------------
        -- if we're close enough to start the end sequence, but the song isn't over,
        -- set up to keep the moon at a distance
        if( dist < ENDSEQUENCE_START and JUST_STARTED.started1 < 3 ) 
        then
          JUST_STARTED.started1 = 3
          forcedForever = vec3.subtract( pos, AsterPos )
          
        end
        
        ------------------------------------------------------------------------
        -- position the moon according to player's position, check for conclusion of song
        if( JUST_STARTED.started1 == 3 )
        then
          ENTITY_SHR_sPosition( ENTITY, AsterPos.x + forcedForever.x, AsterPos.y + forcedForever.y, AsterPos.z + forcedForever.z )
          
        end
        
      end
    
    end
  
  end

  
  ------------------------------------------------------------------------------
  -- the beginning of the end... sequence
  ------------------------------------------------------------------------------
  
  if( endSequence ~= nil )
  then
    ENTITY_SPT_GiveNumber( endSequence, "MoonX", pos.x )
    ENTITY_SPT_GiveNumber( endSequence, "MoonY", pos.y )
    ENTITY_SPT_GiveNumber( endSequence, "MoonZ", pos.z )
    ENTITY_SPT_GiveNumber( endSequence, "MoonR", MIN_RADIUS )
    
  end
  
  
  ------------------------------------------------------------------------------
  -- keep aster from penetrating
  ------------------------------------------------------------------------------
  
  if( dist < MIN_RADIUS )
  then
    AsterVel  = ENTITY_SHR_gVelocity( ASTER )
    x = x / dist
    y = y / dist
    z = z / dist
    local proj = AsterVel.x * x + AsterVel.y * y + AsterVel.z *z
    local VnX = proj * x
    local VnY = proj * y
    local VnZ = proj * z
    local VtX = AsterVel.x - VnX
    local VtY = AsterVel.y - VnY
    local VtZ = AsterVel.z - VnZ
    ENTITY_SHR_sVelocity( ASTER, VnX + FRICTION * VtX, VnY + FRICTION * VtY, VnZ + FRICTION * VtZ )
    x = x * MIN_RADIUS
    y = y * MIN_RADIUS
    z = z * MIN_RADIUS
    ENTITY_SHR_sPosition( ASTER, pos.x + x, pos.y + y, pos.z + z )
  end
  
  ------------------------------------------------------------------------------
  -- keep aster's gravity right
  if( dist < MIN_RADIUS + ATMOSPHERE )
  then
    x = x / dist
    y = y / dist
    z = z / dist
    GLOBAL_SetCameraUpVector( x, y, z )
    x = x * -9.8
    y = y * -9.8
    z = z * -9.8
    ENTITY_PHY_SetAccel( ASTER, x, y, z )
  else
    GLOBAL_SetCameraUpVector( 0, 1, 0 )
    ENTITY_PHY_SetAccel( ASTER, 0, -9.8, 0 )
  end

  ------------------------------------------------------------------------------
  -- Spawn fire flies
  if( myData.SpawnFF ~= nil ) and ( FrameCount <= 0 )
  then
    FrameCount = FRAMECOUNT
    FRAMECOUNT = FRAMECOUNT + FRAMECOUNTINC
    if(FRAMECOUNT > MAXFRAMECOUNT)
    then
      FRAMECOUNT = MAXFRAMECOUNT

    end
    -- Start spawning hell of fireflies
    GLOBAL_FireflySpawnMsg( 200.0, 0.0, 0.0,
                            pos.x, pos.y, pos.z,
                            20,
                            3 )
  end
  FrameCount = FrameCount - 1

end
