/*  
    Crystal Shooter, a first person shooter game engine.
    Homepage: http://members.xoom.com/thieber/cs

    Copyright (C) 1999 Thomas Hieber (thieber@gmx.net)
 
    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. 
 
    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., 675 Mass Ave, Cambridge, MA 02139, USA. 
*/

#include "sysdef.h"
#include "csgame/gstd.h"
#include "csgame/gspr3d.h"

geSprite3D::geSprite3D(gePhysicalObject* pMaster)
 : inherited(pMaster)
{
  m_pMaster       = pMaster;
  m_pSprite       = NULL;
  m_pCollider     = NULL;
  m_AnimateLooped = true;
}

geSprite3D::~geSprite3D()
{
  int idx = m_pWorld->GetCsWorld()->sprites.Find (m_pSprite);
  m_pWorld->GetCsWorld()->sprites[idx] = NULL;
  m_pWorld->GetCsWorld()->sprites.Delete (idx);
  m_pSprite->RemoveFromSectors();

  //will also remove sprite from CS engine. (must be fist, because the
  //destructor will do a last call to its according collider.) 
  delete m_pSprite; 
  
  //Now it is safe to delete to Game Collider.
  delete m_pCollider;
}

void geSprite3D::Create(gePosition Pos, const char* TemplateName, const char* Action)
{
  m_Pos = Pos;

  csSpriteTemplate* tmpl = m_pWorld->GetCsWorld()->GetSpriteTemplate (TemplateName, true);
  ASSERT(tmpl);
  if (!tmpl) return;
  m_pSprite = tmpl->NewSprite ();

  m_pWorld->GetCsWorld()->sprites.Push(m_pSprite);
  m_pSprite->MoveToSector (Pos.GetSector());

  csMatrix3 m; m.Identity (); m = m * 1.0 /*size*/;
  m_pSprite->SetTransform (m);
  m_pSprite->SetAction (Action);
  m_pSprite->SetMove(Pos.GetPosition());

  m_pCollider = new geCollider(m_pWorld, this);
}

void geSprite3D::SetAction(char* Action, bool looped)
{
  ASSERT(m_pSprite);
  m_AnimateLooped = looped;
  m_pSprite->SetAction (Action);
}

void geSprite3D::OnCollision(gePhysicalObject* pOther)
{
  ASSERT(m_pMaster);

  m_pMaster->OnCollision(pOther);

  if (pOther)
  {
    //pOther will be NULL, if it is a Collision with an Object not being
    //controlled by the game logic, but only the CS engine. 
    //Sprites that are used for decoration for instance, and all walls too.
    pOther->OnCollision(m_pMaster);
  }
}

/*void geSprite3D::OnMove(gePosition OldPos)
{
  inherited::OnMove(OldPos);

  ASSERT(m_pSprite);
  ASSERT(m_pCollider);

  m_pSprite->get_mso().init_one_sector(m_Pos.GetSector());
  m_pSprite->set_move(m_Pos.GetPosition());

  gePhysicalObject* pOther = NULL;
  if (m_pCollider->CollisionDetect(pOther))
  {
    OnCollision(pOther);
    m_Pos = OldPos;
  }
}*/

void geSprite3D::OnMove(gePosition OldPos)
{
  inherited::OnMove(OldPos);

  if (m_pSprite)
  {
    m_pSprite->MoveToSector (m_Pos.GetSector());
    m_pSprite->SetMove(m_Pos.GetPosition());
  }
}

bool geSprite3D::FindFirstCollision(csVector3 Offset, gePosition& NewPosition, gePhysicalObject*& pOther)
{
  ASSERT(m_pSprite);
  ASSERT(m_pCollider);

  pOther                   = NULL;
  csVector3 Moved (0, 0, 0);

  int collision = m_pCollider->FindFirstCollision(Offset, 0.2f, Moved, pOther);

  NewPosition.Move(Moved);

  return (collision > 0);
}

void geSprite3D::PrepareFrame(long ElapsedTime, long CurrentTime)
{
  inherited::PrepareFrame(ElapsedTime, CurrentTime);
  if (m_pSprite)
  {
    if (m_pSprite->NextFrame (CurrentTime, false, m_AnimateLooped ? false : true) == true)
    {
      //The current animation has finished
      ASSERT(m_pMaster);
      m_pMaster->OnFinishedAnimation(this);
    }
  }
}
