
/** Podstawowe animacje dla wszystkich stanow ruchu 
 * i wszystkich rodzajow broni.
 * Ma informacje na temat punktu w ktory celuje.
 * Potrafi deformowac swoje cialo tak, aby patrzec w kierunku, w ktorym
 * celuje.
 */
public class PawnAnimated extends Pawn
{
    
///////////////////////////////////////////////////////////////////////////
// A T R Y B U T Y
///////////////////////////////////////////////////////////////////////////
    
    ///////////////////////////////////////////////////////////////////////////
    // Atrybuty zwiazane z animacjami
    ///////////////////////////////////////////////////////////////////////////

    /** Obiekt animacji */
    BaseAnimations CharacterAnims = null;

    /** Plik z definicjami sekwencji animacji */
    //String sAnimIniFile = "Data/Meshes/Logan/logan.scr";

    ///////////////////////////////////////////////////////////////////////////
    // Poruszanie sie
    ///////////////////////////////////////////////////////////////////////////

    int nGravityPhysics = EPhysics._ODE_GRAVITYWALK;//EPhysics._GRAVITYWALK;//
    
    /** Stan ruchu */
    public MotionState motion = null;
    MotionState oldMotion = null; // poprzedni stan ruchu

    /** Aktualna predkosc w lokalnym ukladzie pawna*/
    public Vector   vSpeed = new Vector(0, 0, 0);    

    // Predkosci chodzenia        (still, swim, crawl, duck, walk, run,  ladder climb)
    float aMotionVelocity[]     = {    0,  225,  110,   225,  400,  600,    170};

    // Predkosci cofania sie     
    float aMotionVelocityBack[] = {    0,  100,   50,   150,  315,  475,    100};
    
    // Predkosci strafeowania    
    float aStrafeVelocity[]     = {    0,  125,  110,   225,  250,  525,     50};

    // Przyspieszenie            
    float aMotionAcceleration[] = {    0,   50,  200,   600, 2000, 2500,    800};
    
    /** Masa uzywana w fizyce */
    float fMass = 115.f; //#PAWN
    
    /** Kierunek patrzenia gora/dol */
    float fAimAngleY = 0.f;
    
    
///////////////////////////////////////////////////////////////////////////
// M E T O D Y
///////////////////////////////////////////////////////////////////////////

	public void OnCreate()
    {	
        LogLine("[PlayerAnimated.OnCreate]");
        super.OnCreate();
		
        NetProfiler.Delta("PawnAnimated super.OnCreate");
        
        motion = new MotionState();
        oldMotion = motion;

        SetFlag(EFlags.USE_TERRAIN_LIGHTMAP_FOR_LIGHTING);
        
        //inicjacja fizyki poruszania sie 
        SetPhysicsType( nGravityPhysics );
        SetMaxFallSpeed(new Vector(0, -65000, 0));        
        SetMass(fMass);

        NetProfiler.Delta("PawnAnimated OnCreate");
        
        //inicjacja animacji dla calej postaci
        CharacterAnims = new BaseAnimations(this, "", "Spine", "Spine1", null);
        
        NetProfiler.Delta("PawnAnimated new BaseAnimations");
        
        CharacterAnims.Play( CharacterAnims.A_NONE );
    }

    protected String sLastOtherState = new String("null");
    protected String sLastState      = new String("null");
    protected String sCurrentState   = new String("null");
	
	public	int nCurrentState = EPlayerState.UNKNOWN;
    
    //jesli chcemy ogrniczyc mozliwosc cyklicznego odpalania stanow
    //poprzez zawodanie SetLastOtherState() to ustawiamy to na false
    boolean m_bAllowCircularSetLastOtherState = true;
    //informacja czy poprzednia zmiana stanu byla wywolana poprzez
    //zawolanie SetLastOtherState
    boolean m_bLastStateChangedBySetLastOtherState = false;
    
    //zmienna ustawiana na true podczas wolania SetState z procki
    //SetLastOtherState
    boolean m_bIsStateChangingBySetLastOtherState = false;

    public class PlayerState extends State
    {
        public void OnEnter()
        {
            // przelaczamy odpowiednio nazwy stanow
            sLastState    = sCurrentState;
            sCurrentState = this.getClass().getName();
            
            if ( sCurrentState.compareTo( sLastState ) != 0 )
                sLastOtherState = sLastState;

            //Log("[" + sCurrentState +".OnEnter]\n");

            // wycinamy tylko nazwe stanu
            int nDolar = sCurrentState.indexOf('$');
            sCurrentState = sCurrentState.substring(nDolar+1);
            
            //zapamietujemy czy weszlismy do tego stanu przez
            //zawolanie SetLastOtherState
            m_bLastStateChangedBySetLastOtherState = 
                m_bIsStateChangingBySetLastOtherState;
            //kasujemy ta flaga, bo jak jakis stan u siebie w OnEnter
            //zawola SetState to musi juz byc na false
            m_bIsStateChangingBySetLastOtherState = false;
        }
        
        void SetLastOtherState()
        {
            if ( m_bLastStateChangedBySetLastOtherState && 
                 ! m_bAllowCircularSetLastOtherState )
            {
                CrashLog("ERROR: CircularChangeState "+
                         " sCurrentState: "+sCurrentState+
                         " sLastOtherState: "+sLastOtherState+
                         " !!!, Setting FreehandState\n" );
                SetState( "FreehandState" );
                return;
            }
                
            if ( sCurrentState.compareTo( sLastOtherState ) != 0 )
            {
                m_bIsStateChangingBySetLastOtherState = true;
                SetState( sLastOtherState );
                //kasujemy ta flaga, co prawda jest ona kasowana takze
                //w OnEnter wywolania powyzszego stanu, ale gdyby sie cos 
                //nie zawolalo, to bedzie ok.
                m_bIsStateChangingBySetLastOtherState = false;
            }
            else
            {
                CrashLog("ERROR: sCurrentState == sLastOtherState: "+sLastOtherState+
                         " Setting FreehandState\n" );
                SetState( "FreehandState" );
            }
        }
		//*********************************************************
		//					SaveGame
		//*********************************************************
						
		public void SGUpdate()
		{
			FileChunk.Log("[PawnAnimated$ModeFPP] : SGUpdate\n");
			
			m_bLastStateChangedBySetLastOtherState = false;
		}
		
        public void ComputeAccuracy()
        {
            PawnAnimated.this.ComputeAccuracy();
        }
    }
    
    void ComputeAccuracy()
    {
    }
    
    void Respawn()
    {
        super.Respawn();

        //odtworzenie fizyki
        //inicjacja fizyki poruszania sie 
        SetPhysicsType( nGravityPhysics ); 
        SetMaxFallSpeed(new Vector(0, -65000, 0));
        SetMass(fMass);

    }
 
    
///////////////////////////////////////////////////////////////////////////
// Celowanie
///////////////////////////////////////////////////////////////////////////


    void ShowPos()
    {
        LogD(" "+GetPosition()+"\n");
    }
	
    //*********************************************************
	//					SaveGame
    //*********************************************************
	
    /** Metoda wczytujaca zapisane dane w Save gracza
     */	
    public void SGLoadChunk(FileChunk cParentFC)
    {	
		FileChunk.Log("[PawnAnimated.SGLoadChunk]\n");
		
		FileChunk cFC = GameObject.LoadChunk(cParentFC);   
		
        if (cFC.GetID() == ESGChunksChrome._CHK_PAWN_ANIMATED)
        {
			super.SGLoadChunk(cFC);
			
			// Poruszanie sie

			// stan ruchu
			motion = (MotionState)cFC.LoadObjectRef();
			// poprzedni stan ruchu
			oldMotion = (MotionState)cFC.LoadObjectRef();
						    
			// Masa uzywana w fizyce
			fMass = cFC.LoadFloat();
    
			// Kierunek patrzenia gora/dol
			fAimAngleY = cFC.LoadFloat();			
			
			sLastOtherState = cFC.LoadString();
			sLastState = cFC.LoadString();
			sCurrentState = cFC.LoadString();
			
			// SetState( sCurrentState );
		
			nCurrentState = cFC.LoadInt();
			
			// Aktualna predkosc w lokalnym ukladzie pawna
			vSpeed = cFC.LoadVector();
			
			// zestaw skinow jaki jest zaladowany na mesha, jesli -1 to standardowy
            //To jest tylko do sieci, wiec tu remuje
			//m_nTeamSkinSet = cFC.LoadInt();			
        }
		
		cFC.delete();
	}
	
    /** Metoda zapisujaca dane do Save gracza
     */	
    public void SGSaveChunk(FileChunk cFCParent)
    {
		FileChunk.Log("[PawnAnimated.SGSaveChunk]\n");
		
        FileChunk cFC = NewChunk(ESGChunksChrome._CHK_PAWN_ANIMATED, cFCParent);
		
		super.SGSaveChunk(cFC);
		
		// Poruszanie sie

		// stan ruchu
		cFC.SaveObjectRef(motion);
		// poprzedni stan ruchu
		cFC.SaveObjectRef(oldMotion);
					    
		// Masa uzywana w fizyce
		cFC.SaveFloat(fMass);
    
		// Kierunek patrzenia gora/dol
		cFC.SaveFloat(fAimAngleY);
		
		cFC.SaveString(sLastOtherState);
		cFC.SaveString(sLastState);
		cFC.SaveString(sCurrentState);
		
		cFC.SaveInt(nCurrentState);
		
		// Aktualna predkosc w lokalnym ukladzie pawna
		cFC.SaveVector(vSpeed);    
		
	    // zestaw skinow jaki jest zaladowany na mesha, jesli -1 to standardowy
        //To jest tylko do sieci, wiec tu remuje
		//cFC.SaveInt(m_nTeamSkinSet);
    							
		cFC.delete(); 
	}				
}