//
// Copyright(C) 2014-2015 Samuel Villarreal
//
// 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.
//
// DESCRIPTION:
//      Interactive Anim Object Classes
//

const int8 INTERACTIVE_ANIM_INVISIBLE           = (1 << 0);

const int8 INTERACTIVE_ANIM_MSG_START           = 1;
const int8 INTERACTIVE_ANIM_MSG_INVISIBLE       = 2;
const int8 INTERACTIVE_ANIM_MSG_VISIBLE         = 3;
const int8 INTERACTIVE_ANIM_MSG_CINEMA          = 4;
const int8 INTERACTIVE_ANIM_MSG_SOUND           = 5;
const int8 INTERACTIVE_ANIM_MSG_MUSIC           = 6;
const int8 INTERACTIVE_ANIM_MSG_AMBIENT         = 7;
const int8 INTERACTIVE_ANIM_MSG_SWAP_MODEL      = 8;

//-----------------------------------------------------------------------------
//
// Modes
//
//-----------------------------------------------------------------------------

enum interactiveAnimModes
{
    INTER_ANIM_ALL_MODE     = 1000,
    INTER_ANIM_NOBLEND_MODE = 1001
}

/*
==============================================================
InitInteractiveAnimModeTable
==============================================================
*/

void InitInteractiveAnimModeTable(void)
{
    DefineMode("InitInteractiveAnimModeTable", INTER_ANIM_ALL_MODE,     "", "void MODE_InterAnimTick(void)", CF_STATIC|CF_IGNOREBLOCKERS, 0, "int MODE_InterAnim(void)", 0, 0, 0, 0);
    DefineMode("InitInteractiveAnimModeTable", INTER_ANIM_NOBLEND_MODE, "", "void MODE_InterAnimTick(void)", CF_STATIC|CF_IGNOREBLOCKERS, 0, "int MODE_InterAnim(void)", 0, 0, 0, MF_NO_BLEND);
}

/*
==============================================================
TurokInteractiveAnimation
==============================================================
*/

class TurokInteractiveAnimation : ScriptObject
{
    kActor@     self;
    uint        m_dwFlags;
    int         m_startAnim;
    int         m_activeAnim;
    bool        m_bTriggeredToUnhide;
    
    TurokInteractiveAnimation(kActor@ actor)
    {
        @self = actor;
        m_bTriggeredToUnhide = false;
    }
    
    //--------------------------------------------------
    void OnLevelLoad(kDictMem@ pDict)
    {
        pDict.GetInt("flags", m_dwFlags);
        pDict.GetInt("startAnim", m_startAnim);
    }
    
    //--------------------------------------------------
    void OnSpawn(void)
    {
        // set flag so that they won't get in the way of projectiles
        if(!(self.RenderMeshComponent() is null))
        {
            self.RenderMeshComponent().Flags() |= RMCF_NOEXPANDJOINTS;
        }
        
        self.AddComponent("kexModeStateComponent", true);
        self.ModeStateComponent().AssignModeTable("InitInteractiveAnimModeTable");
        
        if(Game.ActiveMapID() == kLevel_SaveHub)
        {
            self.Mark(false);
        }
        
        self.AnimTrackComponent().MovementClipFlags() = CF_STATIC|CF_IGNOREBLOCKERS;
        
        //----------------------------------------------------------------
        // do nothing if loaded from a save game
        if(self.Deserialized())
        {
            return;
        }
        
        m_activeAnim = m_startAnim;
        self.ModeStateComponent().SetMode(INTER_ANIM_ALL_MODE);
        
        if((m_dwFlags & INTERACTIVE_ANIM_INVISIBLE) != 0)
        {
            self.Flags() |= AF_HIDDEN;
        }
        
        if(!(self.WorldComponent() is null))
        {
            self.WorldComponent().Flags() |= WCF_NONSOLID;
        }
        
        if(self.IsMarked())
        {
            self.Flags() &= ~AF_HIDDEN;
        }
        
        self.EnableComponent("kexEnemyAIComponent", false);
    }
    
    //--------------------------------------------------
    void OnTick(void)
    {
        // stupid bullshit hacks
        switch(self.Type())
        {
        case kActor_AI_SwampTentacle:
        case kActor_AI_Sphincter:
        case kActor_AI_CeilingTentacle:
        case kActor_AI_EyeBallBoss:
        case kActor_AI_QueenPuppet:
            if(!CinemaPlayer.PathTrackPlaying() && (self.Flags() & AF_HIDDEN) == 0)
            {
                self.Flags() |= AF_HIDDEN;
            }
            break;
        default:
            if(!CinemaPlayer.PathTrackPlaying() && m_bTriggeredToUnhide)
            {
                switch(Game.ActiveMapID())
                {
                case kLevel_Ending:
                case kLevel_EndingB:
                    break;
                    
                default:
                    m_bTriggeredToUnhide = false;
                    self.Flags() |= AF_HIDDEN;
                    break;
                }
            }
            break;
        }
        
        self.EnableComponent("kexEnemyAIComponent", false);
        self.RenderMeshComponent().Flags() &= ~RMCF_HEADTRACK;
        
        if(self.Type() == kActor_Cinematic_Common)
        {
            // more stupid-ass hacks
            switch(Game.ActiveMapID())
            {
            case kActor_AI_QueenBoss:
                if(self.AnimTrackComponent().PlayingID() == ANIM_INTER_ANIM5)
                {
                    self.AnimTrackComponent().Flags() &= ~ANF_LOOP;
                }
                break;
            case kLevel_Level1Intro_1:
                if(self.AnimTrackComponent().PlayingID() == ANIM_INTER_ANIM2)
                {
                    self.AnimTrackComponent().Flags() &= ~ANF_BLEND;
                    self.AnimTrackComponent().Flags() |= ANF_NOACCUMULATION;
                }
                break;
            }
            
            
        }
    }
    
    //--------------------------------------------------
    void OnTrigger(kActor@ pInstigator, const int msg)
    {
        switch(self.TriggerMessageID())
        {
        case INTERACTIVE_ANIM_MSG_START:
            //self.Mark(true);
            self.Flags() &= ~AF_HIDDEN;
            
            StartAnim(self.TriggerData());
            
            m_bTriggeredToUnhide = true;
            break;
            
        case INTERACTIVE_ANIM_MSG_INVISIBLE:
            self.Flags() |= AF_HIDDEN;
            //self.Mark(false);
            m_bTriggeredToUnhide = false;
            break;
            
        case INTERACTIVE_ANIM_MSG_VISIBLE:
            self.Flags() &= ~AF_HIDDEN;
            //self.Mark(true);
            //m_bTriggeredToUnhide = true;
            break;
            
        case INTERACTIVE_ANIM_MSG_SOUND:
            self.PlaySound(self.TriggerData());
            break;
            
        case INTERACTIVE_ANIM_MSG_MUSIC:
            Game.PlayMusic(self.TriggerData());
            break;
            
        case INTERACTIVE_ANIM_MSG_AMBIENT:
            World.SetGlobalAmbience(self.TriggerData());
            break;
            
        case INTERACTIVE_ANIM_MSG_SWAP_MODEL:
            self.RenderMeshComponent().SwapOutMesh(self.TriggerData());
            break;
            
        case INTERACTIVE_ANIM_MSG_CINEMA:
            //self.Mark(true);
            self.Flags() &= ~AF_HIDDEN;
            break;
        }
        
        Sys.Print("Interactive anim recieved MSG: " + self.TriggerMessageID() + " with data: " + self.TriggerData());
    }
    
    /*
    ==============================================================
    StartAnim
    ==============================================================
    */
    
    void StartAnim(const int animID)
    {
        // force the mode state component to play a new animation
        self.AnimTrackComponent().Flags() |= ANF_CYCLECOMPLETED;
        
        m_activeAnim = animID;
        self.ModeStateComponent().ForgetAnimState();
        self.ModeStateComponent().SetMode(INTER_ANIM_ALL_MODE, true);
    }
    
    /*
    ==============================================================
    MODE_InterAnim
    ==============================================================
    */
    
    int MODE_InterAnim(void)
    {
        return m_activeAnim;
    }
    
    /*
    ==============================================================
    MODE_InterAnimTick
    ==============================================================
    */
    
    void MODE_InterAnimTick(void)
    {
        if( m_activeAnim >= ANIM_GROUND_ATTACK_COMBAT1 &&
            m_activeAnim <= ANIM_UNDERWATER_COMBO_END5 &&
            self.AnimTrackComponent().CycleCompleted())
        {
            StartAnim(ANIM_GROUND_IDLE1);
        }
    }
};
