/*
* npc.h
*
* Copyright (C) 2003 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.
*
*/

/* This file holds definitions for ALL global variables in the planeshift
* server, normally you should move global variables into the psServer class
*/
#ifndef __NPC_H__
#define __NPC_H__

#include <csutil/hash.h>
#include "npcbehave.h"

class EventManager;
struct iCelEntity;
class  HateList;
struct HateListEntry;
struct iPcLinearMovement;
class iResultRow;
class psTribe;

/**
* This object represents the entities which have attacked or 
* hurt the NPC and prioritizes them.
*/
class HateList
{
protected:
    csHash<HateListEntry*> hatelist;

public:
    HateList() {}

    void AddHate(int entity_id,float delta);
    iCelEntity *GetMostHated(iSector *sector, csVector3& pos, float range);
    bool Remove(int entity_id);
    void DumpHateList();
    void Clear();
    float GetHate(int ent);
};


/**
* This object represents each NPC managed by this superclient.
*/
class NPC
{
protected:
    NPCType           *brain;
    csString           type;
    int                id;
    PS_ID              oldID;
    csString           name;
    csTicks            last_update;
    iCelEntity        *entity;
    iPcLinearMovement *linmove;
    uint8_t            DRcounter;

    csVector3          active_locate_pos;
    float              active_locate_angle;
    float              ang_vel,vel;
    LocationType      *region;
    csString           region_name;
    Perception        *last_perception;
    bool               is_debugging;
    bool               alive;
    int                owner_id;
    uint32_t           target_id;
    psTribe           *tribe;

    // Initial position checks
    csVector3          checkedPos;
    iSector*           checkedSector;
    bool               checked;
    bool               checkedResult;

    csList<Waypoint*>  waypoint_list;
    
public:
    HateList           hatelist;
    
    NPC();
    ~NPC();

    int GetID()                       { return id; }
    iCelEntity *GetEntity()           { return entity; }
    iPcLinearMovement *GetLinMove()   { return linmove; }
    uint8_t               GetDRCounter() { return ++DRcounter;}
    void               SetDRCounter(uint8_t counter) { DRcounter = counter;}

    // bool Load(iDocumentNode *node,BinaryRBTree<NPCType>& npctypes);
    bool Load(iResultRow& row,BinaryRBTree<NPCType>& npctypes);
    bool InsertCopy(int use_char_id);

    void SetEntity(iCelEntity *ent);
    csString& GetName() {return name;}
    void SetAlive(bool a) { alive = a; }
    bool IsAlive() { return alive; }

    Behavior *GetCurrentBehavior() { return brain->GetCurrentBehavior(); }
    NPCType  *GetBrain() { return brain; }
    
    void DumpBehaviorList(bool force=false);
    void DumpHateList(bool force=false);

    void ClearState();

    void Advance(csTicks when,EventManager *eventmgr);
    void ResumeScript(EventManager *eventmgr,Behavior *which);

    void TriggerEvent(Perception *pcpt,EventManager *eventmgr);
    void SetLastPerception(Perception *pcpt);
    Perception *GetLastPerception() { return last_perception; }

    iCelEntity *GetMostHated(float range);
    float       GetEntityHate(iCelEntity *ent);
    void AddToHateList(iCelEntity *attacker,float delta);
    void RemoveFromHateList(PS_ID who);

    void SetActiveLocate(csVector3& pos,float rot)
    { active_locate_pos=pos; active_locate_angle=rot; }

    void GetActiveLocate(csVector3& pos,float& rot)
    { pos=active_locate_pos; rot=active_locate_angle; }

    void WaypointListClear() { waypoint_list.DeleteAll(); }
    void WaypointListPushBack(Waypoint * wp) { waypoint_list.PushBack(wp); }
    bool WaypointListActivateFirst();
    Waypoint * WaypointListGetNext();
    bool WaypointListEmpty() { return waypoint_list.IsEmpty(); }
    csList<Waypoint*> WaypointListGet() { return waypoint_list; }
    
    bool SwitchDebugging()
    {
        is_debugging = !is_debugging;
        return is_debugging;
    }
    
    void SetDebugging(bool debug)
    {
        is_debugging = debug;
    }
    
    float GetAngularVelocity()
    {
        if (ang_vel == 999)
            return brain->GetAngularVelocity();
        else
            return ang_vel;
    }

    float GetVelocity()
    {
        if (vel == 999)
            return brain->GetVelocity();
        else
            return vel;
    }

    LocationType *GetRegion();

    void GetNearestEntity(uint32_t& target_id,csVector3& dest,csString& name,float range);

    iCelEntity * GetNearestVisibleFriend(float range);

    void Printf(const char *msg,...);

    iCelEntity *GetTarget();
    void SetTarget(iCelEntity *ent);

    iCelEntity *GetOwner();
    void SetOwnerID( int owner ) { owner_id = owner; };
    csString GetOwnerName();

    /** Set a new tribe for this npc */
    void SetTribe(psTribe * new_tribe);
    /** Get the tribe this npc belongs to. Null if not part of a tribe */
    psTribe * GetTribe();
    

    bool IsDebugging() { return is_debugging;};

    void CheckPosition();
};

struct HateListEntry
{
    int   entity_id;
    float hate_amount;
};


#endif

