/*
===========================================================================
Copyright (C) 2015 the OpenMoHAA team

This file is part of OpenMoHAA source code.

OpenMoHAA source code 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.

OpenMoHAA source code 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 OpenMoHAA source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

// windows.cpp: Window class
//

#include "g_phys.h"
#include "windows.h"
#include "game.h"

Event EV_Window_Setup
(
    "_Windowsetup",
    EV_CODEONLY,
    NULL,
    NULL,
    "Does the post spawn setup of the Window"
);

Event EV_Window_SetDebris
(
    "debristype",
    EV_DEFAULT,
    "i",
    "type",
    "Sets the debris type of the Window"
);

CLASS_DECLARATION(Entity, WindowObject, "func_window") {
    {&EV_Window_Setup,     &WindowObject::WindowSetup     },
    {&EV_Damage,           &WindowObject::WindowDamaged   },
    {&EV_Killed,           &WindowObject::WindowKilled    },
    {&EV_Window_SetDebris, &WindowObject::WindowDebrisType},
    {NULL,                 NULL                           }
};

WindowObject::WindowObject()
{
    if (LoadingSavegame) {
        return;
    }

    edict->s.eType = ET_GENERAL;
    health         = 250;
    max_health     = health;
    deadflag       = 0;
    takedamage     = DAMAGE_YES;

    m_iDebrisType = WINDOW_GLASS;

    PostEvent(EV_Window_Setup, EV_POSTSPAWN);
}

void WindowObject::Archive(Archiver& arc)
{
    Entity::Archive(arc);

    arc.ArchiveInteger(&m_iDebrisType);
    arc.ArchiveString(&m_sBrokenModel);
}

void WindowObject::WindowSetup(Event *ev)
{
    Entity *pEnt;

    setMoveType(MOVETYPE_NONE);
    setSolidType(SOLID_BSP);
    setContents(CONTENTS_TRIGGER);

    if (Target().length()) {
        // If a target is defined,
        // find it and set the model from it
        pEnt = (Entity *)G_FindTarget(NULL, Target());

        if (pEnt) {
            m_sBrokenModel = pEnt->model;

            // Don't keep the original entity
            pEnt->PostEvent(EV_Remove, 0);
        }
    }
}

void WindowObject::WindowDebrisType(Event *ev)
{
    m_iDebrisType = ev->GetInteger(1);
}

void WindowObject::WindowDamaged(Event *ev)
{
    int    iMeansOfDeath;
    int    iDamage;
    Vector vRight;
    Vector vForward;
    Vector vDir;
    Event *event;

    if (!takedamage) {
        return;
    }

    iDamage       = ev->GetInteger(2);
    iMeansOfDeath = ev->GetInteger(9);

    if (iMeansOfDeath == MOD_BASH) {
        // double damage for bash
        iDamage *= 2;
    } else if (iMeansOfDeath == MOD_EXPLOSION) {
        // instant break
        iDamage *= 10;
    }

    health -= iDamage;

    if (health <= 0.0f) {
        event = new Event(EV_Killed);

        event->AddEntity(ev->GetEntity(1));
        event->AddInteger(ev->GetInteger(2));
        event->AddEntity(ev->GetEntity(3));

        ProcessEvent(event);
    }
}

void WindowObject::WindowKilled(Event *ev)
{
    Vector vCenter;

    setSolidType(SOLID_NOT);

    hideModel();
    takedamage = DAMAGE_NO;

    vCenter = (mins + maxs) * 0.5;
    vCenter += origin;

    gi.SetBroadcastVisible(vCenter, vCenter);
    gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_MAKE_WINDOW_DEBRIS));
    gi.MSG_WriteCoord(vCenter[0]);
    gi.MSG_WriteCoord(vCenter[1]);
    gi.MSG_WriteCoord(vCenter[2]);
    gi.MSG_WriteByte(m_iDebrisType);
    gi.MSG_EndCGM();

    if (m_sBrokenModel.length()) {
        Entity *ent = new Entity;

        ent->takedamage = DAMAGE_NO;
        ent->setModel(m_sBrokenModel);

        ent->setMoveType(MOVETYPE_NONE);
        ent->setSolidType(SOLID_BSP);

        setModel(m_sBrokenModel);

        if (spawnflags & WINDOW_BROKEN_BLOCK) {
            ent->setContents(CONTENTS_MONSTERCLIP | CONTENTS_PLAYERCLIP);
        } else {
            ent->setContents(CONTENTS_SHOOTONLY);
        }

        ent->setOrigin(origin);
        ent->showModel();
    }

    deadflag = DEAD_DEAD;

    // remove the window
    PostEvent(EV_Remove, 0);
}
