/*
 * servervitals.h
 *
 * Copyright (C) 2005 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
 *
 *
 * 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 (version 2 of the License)
 * 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.
 *
 */

#include <psconfig.h>

#include "servervitals.h"
#include "../gem.h"
#include "pscharacter.h"
#include "net/msghandler.h"

psServerVitals::psServerVitals(psCharacter * character)
{
    this->character = character;
    statsDirty = 0;
    version    = 0;
}

bool psServerVitals::ConstructDRData(MsgEntry* me, int flags)
{
    bool backup=0;
    if (flags)
    {
        backup = statsDirty ? true : false;
        statsDirty = flags;
    }
    else if (version%10==0)  // every 10th msg to this person, send everything
        statsDirty = DIRTY_VITAL_ALL;

    // Allways add the stat word. Else you will not know how much to read.
    me->Add((uint32_t)statsDirty);
        
    if (!statsDirty) 
        return false;
    
    if (statsDirty & DIRTY_VITAL_HP)
        me->Add( vitals[VITAL_HITPOINTS].value / vitals[VITAL_HITPOINTS].max );
        
    if (statsDirty & DIRTY_VITAL_HP_RATE)
        me->Add( vitals[VITAL_HITPOINTS].drRate / vitals[VITAL_HITPOINTS].max );
        
    if (statsDirty & DIRTY_VITAL_MANA)
        me->Add( vitals[VITAL_MANA].value / vitals[VITAL_MANA].max ); 
         
    if (statsDirty & DIRTY_VITAL_MANA_RATE)
        me->Add( vitals[VITAL_MANA].drRate / vitals[VITAL_MANA].max );
        
    // Pyshical Stamina
    if (statsDirty & DIRTY_VITAL_PYSSTAMINA)
        me->Add( vitals[VITAL_PYSSTAMINA].value / vitals[VITAL_PYSSTAMINA].max );                

    if (statsDirty & DIRTY_VITAL_PYSSTAMINA_RATE)
        me->Add( vitals[VITAL_PYSSTAMINA].drRate / vitals[VITAL_PYSSTAMINA].max );

    // Mental Stamina
    if (statsDirty & DIRTY_VITAL_MENSTAMINA)
        me->Add( vitals[VITAL_MENSTAMINA].value / vitals[VITAL_MENSTAMINA].max );                

    if (statsDirty & DIRTY_VITAL_MENSTAMINA_RATE)
        me->Add( vitals[VITAL_MENSTAMINA].drRate / vitals[VITAL_MENSTAMINA].max );

    if (statsDirty & DIRTY_VITAL_EXPERIENCE)
        me->Add( (int32_t)GetExp() );
                
    if (statsDirty & DIRTY_VITAL_PROGRESSION)
        me->Add( (int32_t)GetPP() );

    // HACK to test statDR versioning--KWF
    //if (version%10==0)
    //{
    //    version-=2;
    //    me->Add((uint8_t)++version);
    //    version+=2;
    //}
    //else
    me->Add((uint8_t)++version);
    
    // printf("Sending StatDR version %d for entity.\n", version);

    statsDirty = backup;    
    return true;
}


bool psServerVitals::Update( csTicks now )
{
    csTicks drdelta = now - lastDRUpdate;
    float delta;
    /* It is necessary to check when lastDRUpdate is 0 because, if not when a character login his stats
    are significantly incremented, which is instead unnecessary. As tested, delta cannot be 0 or the actors
    with 0 HP and negative drRate will enter a loop of death, but it has to be really small in order to guarantee
    a smooth increment of the stats. Since, now can be quite a random value when lastDRUpdate is 0, it is important
    to give an high value to drdelta, so we can force a stats update.*/
    if(!lastDRUpdate) 
    {
        delta=0.1f; //The value can be adjusted but it has to be really small.
        drdelta= 11000; //drdelta must be really high, in order to avoid randomness and guarantee stats update
    }
    else
       delta= (now-lastDRUpdate)/1000.0;
    lastDRUpdate = now;

    // iterate over all fields and predict their values based on their recharge rate
    for ( int x = 0; x < VITAL_COUNT; x++ )
    {
        vitals[x].value += vitals[x].drRate*delta;            
        
        if ( vitals[x].value < 0 )
            vitals[x].value = 0;
        if ( vitals[x].value > vitals[x].max )
            vitals[x].value = vitals[x].max;                
    }        

    if (vitals[VITAL_HITPOINTS].value==0  &&  vitals[VITAL_HITPOINTS].drRate<0)
        character->GetActor()->Kill(NULL);
    
    if (drdelta > 10000)
        statsDirty = QUERY_FAILED;

    return (statsDirty) ? true : false;
}


void psServerVitals::SetExp( int W )
{
    experiencePoints = W;
    statsDirty |= DIRTY_VITAL_EXPERIENCE;
}

void psServerVitals::SetPP( int pp )
{
    progressionPoints = pp;
    statsDirty |= DIRTY_VITAL_PROGRESSION;
}

psCharVital& psServerVitals::DirtyVital( int vitalName, int dirtyFlag )
{
    statsDirty |= dirtyFlag;
    return GetVital( vitalName );    
}

