/*   Copyright 2005,2006 Paweł Niegowski
*
*    This file is part of Fenrir.
*
*    Fenrir 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.
*
*    Fenrir 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 Fenrir; if not, write to the Free Software
*    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "main.h"
#include "object.h"
#include "network.h"
#include "player.h"
#include "particle.h"
#include "play.h"
#include "console.h"
#include "map.h"
#include <list>
using namespace std;

list<Object*> object_list;

bool drawing_upper_layer = false;

Object::Object()
: speed(2.666), kill_counter(-1), lifetime(-1), show_delay(0), direction(DIR_DOWN), x(0), y(0), high_offset(0), sort_y(0), evade_counter(0), net_x(-1), net_y(0), obj_num(0), visible(false), remove(false), targetable(false), dead(false), sitting(false), stunlock(0)
{
 object_list.push_back(this);
 newmap = network_disabled;
}

Object::~Object()
{
 for(list<Animator*>::iterator it = animators.begin(); it != animators.end(); it++)
  delete (*it);
}

void Object::run_animators()
{
 for(list<Animator*>::iterator it = animators.begin(); it != animators.end(); it++)
  (*it)->animate(this);
 for(list<Animator*>::iterator it = animators.begin(); it != animators.end(); it++)
  if((*it)->remove)
  { delete (*it); animators.erase(it); it = animators.begin(); }
}

void Object::_attack(int target, Packet *attack_data)
{
 unsigned char *data = attack_data->data + 3;
 int hit_count = (data[0]) >> 5;
 unsigned int dmg = 0;
 int connected_hits = 0;
 float vx = (rand()%200)/100.0 - 1.0;
 float vy =  (rand()%100)/-50.0 - 3.0;
 bool pushback = false;
 //pushback
 if(data[0] & 16 && !network_disabled)
 {
  pushback = true;
  objects[target]->net_x = data[2] * 16;
  objects[target]->net_y = data[3] * 16;
  objects[target]->stunlock = 30;
 }
 for(int i = 0; i < hit_count; i++)
 {
  //connected
  if(data[1] & (1<<i))
  {
   dmg = 0;
   memcpy(&dmg, data+2+connected_hits*2 + (pushback?2:0), 2);
   objects[target]->get_dmg(dmg,10*i,vx,vy);
   connected_hits++;
  } else
   objects[target]->evade(30);
  combat_hit(target,attack_data,i);
 }
 attack_data->data += 5 + (pushback?2:0) + connected_hits*2;
 attack_data->length -= 5 + (pushback?2:0) + connected_hits*2;
}

class _ObjectSorter
{
 public:
 bool operator()(Object *a, Object *b)
 { return drawing_upper_layer?(a->sort_y+a->high_offset < b->sort_y+b->high_offset) : (a->sort_y < b->sort_y); }
};

void object_list_think()
{
 for(list<Object*>::iterator it = object_list.begin(); it != object_list.end(); it++)
  if(!(*it)->newmap)
  {
   (*it)->run_animators();
   (*it)->think();
  }


 for(list<Object*>::iterator it = object_list.begin(); it != object_list.end();)
  if((*it)->remove)
  {
   delete (*it);
   object_list.erase(it);
   it = object_list.begin();
  } else it++;
}

void object_list_draw_top()
{
 for(list<Object*>::iterator it = object_list.begin(); it != object_list.end(); it++)
  if(!(*it)->newmap)
   (*it)->draw_top();
 if(key[keymap[KEYMAP_R]] && !key[keymap[KEYMAP_L]] && !console_active && !menu_active)
  for(list<Object*>::iterator it = object_list.begin(); it != object_list.end(); it++)
   if(!(*it)->newmap)
    (*it)->display_name();
}

void object_list_draw_upper()
{
 drawing_upper_layer = true;
 object_list.sort(_ObjectSorter());
 for(list<Object*>::iterator it = object_list.begin(); it != object_list.end(); it++)
  if(!(*it)->newmap)
   (*it)->draw_upper();
}

void object_list_draw_lower()
{
 drawing_upper_layer = false;
 object_list.sort(_ObjectSorter());
 for(list<Object*>::iterator it = object_list.begin(); it != object_list.end(); it++)
  if(!(*it)->newmap)
   (*it)->draw_lower();
}

void object_list_cleanup()
{
 for(list<Object*>::iterator it = object_list.begin(); it != object_list.end(); it++)
  delete (*it);
 object_list.clear();
}

void RemoveAnimator::animate(Object *o)
{
 life--;
 if(life < 0 && o->kill_counter == -1) o->kill_counter = KILL_DELAY;
}

void AttachAnimator::animate(Object *o)
{
 o->setx(o->getx() + target->getx() - x);
 o->sety(o->gety() + target->gety() - y);
 x = target->getx();
 y = target->gety();
 if(o->show_delay == 0 && remove_when_visible)
  remove = true;

}
