/*
* perceptions.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 __PERCEPTIONS_H__
#define __PERCEPTIONS_H__

#include <csgeom/matrix3.h>
#include <csutil/weakref.h>

#include <physicallayer/entity.h>

#include <util/prb.h>
#include <csutil/array.h>
#include <iutil/document.h>
#include "util/eventmanager.h"
#include "util/psconst.h"

class ScriptOperation;
class Perception;
class Behavior;
class NPC;
class EventManager;
class BehaviorSet;
struct iCelEntity;

/**
* A reaction embodies the change in desire which occurs
* in an NPC when he perceives something.
*/
class Reaction
{
protected:
    // members making up the "if statement"
    csString  event_type;
    float     range;
    int          faction_diff;
    csString  oper;
    bool      inactive_only;
    int       time;

    // members making up the "then statement"
    Behavior *affected;
    float delta_desire;
    float weight;

public:
    Reaction();
    Reaction(Reaction& other,BehaviorSet& behaviors) 
    { DeepCopy(other,behaviors); }

    void DeepCopy(Reaction& other,BehaviorSet& behaviors);

    bool Load(iDocumentNode *node,BehaviorSet& behaviors);
    void React(NPC *who,EventManager *eventmgr,Perception *pcpt);

    const char *GetEventType()    { return event_type;   }
    float       GetRange()        { return range;        }
    int         GetFactionDiff()  { return faction_diff; }
    int         GetReactTime()    { return time;         }
    char        GetOp()           { if (oper.Length()) return oper.GetAt(0); else return 0; }
};


/**
* This embodies any perception an NPC might have,
* or any game event of interest.  Reaction objects
* below will subscribe to these events, and the
* networking system will publish them.  Examples
* would be "attacked", "collided", "talked to",
* "hear cry".
*/
class Perception
{
protected:
    csString name;

public:
    Perception(const char *n) { name = n; }
    virtual ~Perception() {}
    const char *GetName() { return name; }

    virtual bool ShouldReact(Reaction *reaction,NPC *npc) { return name == reaction->GetEventType(); }
    virtual Perception *MakeCopy();
    virtual bool GetLocation(csVector3& pos) { return false; }
    virtual void ExecutePerception(NPC *npc,float weight) { }
  
    virtual iCelEntity *GetEntity() { return NULL; }
};

class RangePerception : public Perception
{
protected:
    float range;

public:
    RangePerception(const char *n,float r)
    : Perception(n), range(r)  {    }
    virtual ~RangePerception() {}

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
};

class TimePerception : public Perception
{
protected:
    int time;

public:
    TimePerception(const char *n,int t)
    : Perception(n), time(t)  {    }
    virtual ~TimePerception() {}

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
};

class FactionPerception : public Perception
{
protected:
    int faction_delta;
    csWeakRef<iCelEntity> player;

public:
    FactionPerception(const char *n,int d,iCelEntity *p)
    : Perception(n), faction_delta(d), player(p)  {    }
    virtual ~FactionPerception() {}

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
    virtual bool GetLocation(csVector3& pos);
    virtual iCelEntity *GetEntity() { return player; }
    virtual void ExecutePerception(NPC *npc,float weight);
};

/**
 * Whenever an NPC is close to an item, this perception is
 * passed to the npc.
 */
class ItemPerception : public Perception
{
protected:
    csWeakRef<iCelEntity> item;

public:
    ItemPerception(const char *n,iCelEntity *i)
    : Perception(n), item(i)  {    }
    virtual ~ItemPerception() {}

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
    virtual bool GetLocation(csVector3& pos);
    virtual iCelEntity *GetEntity() { return item; }
};

/**
 * Whenever an NPC is attacked by a player, this perception is
 * passed to the attacked npc.  The npc should use this to build
 * an initial hate list for the player and his group (if any).
 * If the designer wants to cheat, he can start attacking back
 * on this event instead of on first damage, and save a few seconds
 * in response time.
 */
class AttackPerception : public Perception
{
protected:
    csWeakRef<iCelEntity> attacker;

public:
    AttackPerception(const char *n,iCelEntity *attack)
        : Perception(n), attacker(attack) { }

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
    virtual void ExecutePerception(NPC *npc,float weight);
    virtual iCelEntity *GetEntity() { return attacker; }
};

/**
 * Whenever an NPC is attacked by a grouop, this perception is
 * passed to the attacked npc.  The npc should use this to build
 * an initial hate list for the player group.
 * If the designer wants to cheat, he can start attacking back
 * on this event instead of on first damage, and save a few seconds
 * in response time.
 */
class GroupAttackPerception : public Perception
{
protected:
    iCelEntity *attacker;
    csArray<iCelEntity *> attacker_ents;
    csArray<int> bestSkillSlots;

public:
    GroupAttackPerception(const char *n,csArray<iCelEntity *> & ents, csArray<int> & slots)
        : Perception(n), attacker_ents(ents), bestSkillSlots(slots) { }

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
    virtual void ExecutePerception(NPC *npc,float weight);
};

/**
 * Whenever an NPC is hit for damage by a melee hit or a spell,
 * this perception is passed to the damaged npc.  Right now,
 * it affects his/her hate list according to the weight supplied.
 */
class DamagePerception : public Perception
{
protected:
    iCelEntity *attacker;
    float damage;

public:
    DamagePerception(const char *n,iCelEntity *attack,float dmg)
        : Perception(n), attacker(attack), damage(dmg) { }

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
    virtual void ExecutePerception(NPC *npc,float weight);
};

/**
 * Whenever a player casts a spell on himself, another player,
 * or any npc, this perception is passed to npc's in the vicinity.
 * We cannot only use targeted NPCs because an npc in combat may
 * want to react to a player healing his group mate, which helps
 * his team and hurts the NPC indirectly.  Right now, reactions
 * are allowed by type of spell, and depending on the severity,
 * it affects his/her hate list according to the weight supplied.
 */
class SpellPerception : public Perception
{
protected:
    iCelEntity *caster;
    iCelEntity *target;
    float       spell_severity;
    csString    spell_type_str;

public:
    SpellPerception(const char *name,iCelEntity *caster,iCelEntity *target, const char *spell_type, float severity);

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
    virtual void ExecutePerception(NPC *npc,float weight);
};

/**
 * The network layer is notified of any deaths from players
 * or NPCs on the server.  This perception is passed to all
 * NPCs so they can react, by removing the player from hate
 * lists, stopping their combat or whatever.
 */
class DeathPerception : public Perception
{
protected:
    PS_ID who;

public:
    DeathPerception(const char *n,PS_ID ent_id)
        : Perception(n), who(ent_id) { }

    virtual bool ShouldReact(Reaction *reaction,NPC *npc);
    virtual Perception *MakeCopy();
    virtual void ExecutePerception(NPC *npc,float weight);
};


/// NPC Pet Perceptions ============================================
/**
 * Whenever an NPCPet is told by it's owner to stay,
 * this perception is passed to the NPCPet.  Right now,
 * it changes the current behavior of the NPCPet.
 */
class OwnerCmdPerception : public Perception
{
protected:
    int command;
    iCelEntity *owner;
    iCelEntity *pet;

public:
    OwnerCmdPerception(const char *n, int command, iCelEntity *owner, iCelEntity *pet );

    enum 
    {
		OCP_FOLLOW,
		OCP_STAY,
		OCP_DISMISS,
		OCP_SUMMON,
		OCP_ATTACK,
        OCP_STOPATTACK,
		OCP_GUARD,
		OCP_ASSIST,
		OCP_NAME,
		OCP_TARGET
    };

    virtual bool ShouldReact( Reaction *reaction, NPC *pet );
    virtual Perception *MakeCopy();
    virtual void ExecutePerception( NPC *pet, float weight );
};

/**
 * Whenever an NPCPet is told by it's owner to stay,
 * this perception is passed to the NPCPet.  Right now,
 * it changes the current behavior of the NPCPet.
 */
class OwnerActionPerception : public Perception
{
protected:
    int action;
    iCelEntity *owner;
    iCelEntity *pet;

public:
    OwnerActionPerception(const char *n, int action, iCelEntity *owner, iCelEntity *pet );

    virtual bool ShouldReact( Reaction *reaction, NPC *pet );
    virtual Perception *MakeCopy();
    virtual void ExecutePerception( NPC *pet, float weight );
};
/// NPC Pet Perceptions ============================================
#endif

