/*
**  Copyright (C) 1996, 1997 Microsoft Corporation. All Rights Reserved.
**
**  File:	shieldIGC.cpp
**
**  Author: 
**
**  Description:
**      Implementation of the CshieldIGC class. This file was initially created by
**  the ATL wizard for the core object.
**
**  History:
*/
// shieldIGC.cpp : Implementation of CshieldIGC
#include "pch.h"
#include "shieldIGC.h"

/////////////////////////////////////////////////////////////////////////////
// CshieldIGC
CshieldIGC::CshieldIGC(void)
:
    m_partType(NULL),
    m_ship(NULL),
    m_fraction(0.0f),
    m_mountID(c_mountNA)
{
}

HRESULT     CshieldIGC::Initialize(ImissionIGC* pMission, Time now, const void* data, int dataSize)
{
    m_pMission = pMission;

    ZRetailAssert (data && (dataSize == sizeof(DataPartIGC)));
    {
        m_partType = ((DataPartIGC*)data)->partType;
        assert (m_partType);
        m_partType->AddRef();

        m_typeData = (const DataShieldTypeIGC*)m_partType->GetData();
    }

	return S_OK;
}

void        CshieldIGC::Terminate(void)
{
    AddRef();

    SetShip(NULL, NA);

    if (m_partType)
    {
        m_partType->Release();
        m_partType = NULL;
    }

    Release();
}

void        CshieldIGC::Update(Time now)
{
    assert (m_ship);
    assert (m_mountID == 0);

    Time    lastUpdate = m_ship->GetLastUpdate();
    assert (now >= lastUpdate);

    float dt = now - lastUpdate;


    if (m_mountedFraction < 1.0f)
    {
        //We can't assert that the shield fraction is 0 because
        //the shield fraction is directly set via updates from the server
        //and the server times for mounting/dismounting might be different
        //from this client
        
        m_mountedFraction += dt * m_pMission->GetFloatConstant(c_fcidMountRate);
        if (m_mountedFraction < 1.0f)
            return;

        IIgcSite*   pigc = m_pMission->GetIgcSite();
        pigc->PlayNotificationSound(mountedSound, m_ship);
        pigc->PostNotificationText(m_ship, false, "%s ready.", GetPartType()->GetName());
        m_mountedFraction = 1.0f;
    }

    float previousFraction = m_fraction;

    //Use set fraction so that the ship's shape will change if appropriate
    SetFraction(m_fraction + GetRegeneration() * dt / GetMaxStrength());

    // if we have managed to recharge above 5%, play a shield-powerup sound
    if (previousFraction < 0.05 && m_fraction >= 0.05)
        m_pMission->GetIgcSite()->PlaySoundEffect(m_typeData->activateSound, m_ship);

}
void        CshieldIGC::SetShip(IshipIGC*       newVal, Mount mount)
{
    //There may be only a single reference to this part ... so make sure the part
    //does not get deleted midway through things
    AddRef();

    if (m_ship)
    {
        m_ship->DeletePart(this);
        m_ship->Release();
    }
    assert (m_mountID == c_mountNA);
    m_ship = newVal;

    if (m_ship)
    {
        m_ship->AddRef();
        m_ship->AddPart(this);

        SetMountID(mount);
    }

    Release();
}
void    CshieldIGC::SetMountID(Mount newVal)
{
    assert (m_ship);

    if (newVal != m_mountID)
    {
        if ((newVal < 0) && (m_mountID == 0))
            Deactivate();

        m_ship->MountPart(this, newVal, &m_mountID);

        if (newVal == 0)
        {
            m_fraction = 0.0f;
            Activate();         //If it is mounted ... it is active
        }
    }
}

float   CshieldIGC::ApplyDamage(Time           timeCollision,
                                DamageTypeID   type,
                                float          amount,
                                const Vector&  deltaP)
{
    float   dtm = m_pMission->GetDamageConstant(type, m_typeData->defenseType);
    amount *= dtm;

    float leakage;

    if (amount > 0.0)
    {
        assert (dtm > 0.0f);

        //how much damage will the shield actually stop?
        float   maxStrength = GetMaxStrength();
        float   absorbed = amount / maxStrength;

        float down = m_pMission->GetFloatConstant(c_fcidDownedShield);

        if (m_fraction <= down)
        {
            //The shield was previously knocked negative ... it doesn't absorb anything
            leakage = amount / dtm;
        }
        else
        {
            float   usefulShieldFraction = m_fraction - down;
            assert (usefulShieldFraction >= 0.0f);

            if ((type & c_dmgidNoFlare) == 0)
                m_ship->GetThingSite()->AddFlare(timeCollision, deltaP, 0, m_ship->GetHitTest()->GetEllipseEquation());

            if (absorbed <= usefulShieldFraction)
            {
                //Normal case ... the shield is strong enough to abosrb the entire hit
                leakage = 0.0f;
            }
            else
            {
                //Abnormal case ... the shield isn't strong enough: so use normal shield behavior on the
                //portion that can be absorbed and apply the rest as leakage.
                leakage = (absorbed - usefulShieldFraction) * maxStrength / dtm;
                assert (leakage >= 0.0f);

                m_pMission->GetIgcSite()->PlaySoundEffect(m_typeData->deactivateSound, m_ship);
                m_pMission->GetIgcSite()->PlayNotificationSound(salShieldsOfflineSound, m_ship);
            }
        }
        SetFraction(m_fraction - absorbed);
    }
    else
        leakage = 0.0f;

    return leakage;
}