/*
 * server/Character.h:
 *
 * Copyright (C) 2000 John Watson, jwatson@tempusmud.com
 * 
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */

#ifndef __Character_h__
#define __Character_h__

#include "Entity.h"

enum CharacterStat {
        STAT_STR,
        STAT_DEX,
        STAT_SPD,
        STAT_CON,
        STAT_CHA,
        NUM_STATS
};

enum WornPosition {
        WEAR_NONE,
        WEAR_HEAD,
        WEAR_BODY,
        WEAR_ARMS,
        WEAR_HANDS,
        WEAR_WAIST,
        WEAR_LEGS,
        WEAR_FEET,
        WEAR_HOLDLEFT,
        WEAR_HOLDRIGHT,
        WEAR_WIELD,
        NUM_WORN_POSITIONS
};

enum AffectFlag {
        AFF_NONE         = 0x0000,
        AFF_SUPER_DAMAGE = 0x0001,
        AFF_SPEED        = 0x0002,
        AFF_PROTECTION   = 0x0004,
        NUM_AFF_FLAGS    = 4
};

class Character : public Entity {
        
        class Entity * _targetEntity;

        /** the attributes/stats of the character */
        unsigned char _stats[ NUM_STATS ];
        
        /** the current Armor Class of this character */
        unsigned char _AC;
        /** the maximum number of HitPoints on this character */
        short _maxHPs;
        /** the current number of HitPoints on this character */
        short _curHPs;
        
        /** how much gold this character is carrying */
        unsigned short _gold;
        /** how much xp this character is worth for killing */
        unsigned short _expValue;
        /** how much exp this character has toward next level */
        unsigned short _exp;

        /** how many skillpoints the character has to spend */
        unsigned char _skillPoints;

        short _eyeLevel;

        /** character's worn items 
         * @supplierCardinality NUM_WORN_POSITIONS
         * @label equipment*/
        class Item * _eq[ NUM_WORN_POSITIONS ];
        
        /** total weight of equipment */
        int _wornWeight;
        
        /** temporary flags which affect character performance*/
        unsigned int _affectFlags;
        
        /** affs which are currently placed upon this character and can wear off */
        class Vector< class CharacterAffect * > _affs;
       
        unsigned char _level;

        void init();

protected:

        unsigned int _lastFootstepTick;
        unsigned int _footstepTickMin;

        char * _weaponModelName;
        char * _weaponSkinName;

        /**
         * utility.. removes an item from equipment, leaving it in an undefined state
         */

        bool itemFromEquipment( class Item * item );
        
        bool itemToEquipment( class Item * item, WornPosition pos );

        bool itemFromInventory( class Item * item );

        /**
         * moves an item from  inventory  to equipment, moving the currently equipped
         * item to the inventory or another eq pos, if applicable.
         *
         * returns false if the item is invalid or inappropriate, or an error occurs
         *
         * if the target equipment pos is empty, this call is equivalent to equipItem()
         */ 
        bool reEquipItemFromInventory( class Item * item, WornPosition pos );

        /**
         * moves an item from one inventory slot to another
         *
         * returns false if the item is invalid or inappropriate, or an error occurs
         *
         */ 
        bool reEquipItemFromEquipment( class Item * item, WornPosition pos );

        int _viewFrame;
        bool _viewFrameUp;

public:

        static const int FRAME_stand01 = 0;
        static const int FRAME_stand02 = 1;
        static const int FRAME_stand03 = 2;
        static const int FRAME_stand04 = 3;
        static const int FRAME_stand05 = 4;
        static const int FRAME_stand06 = 5;
        static const int FRAME_stand07 = 6;
        static const int FRAME_stand08 = 7;
        static const int FRAME_stand09 = 8;
        static const int FRAME_stand10 = 9;
        static const int FRAME_stand11 = 10;
        static const int FRAME_stand12 = 11;
        static const int FRAME_stand13 = 12;
        static const int FRAME_stand14 = 13;
        static const int FRAME_stand15 = 14;
        static const int FRAME_stand16 = 15;
        static const int FRAME_stand17 = 16;
        static const int FRAME_stand18 = 17;
        static const int FRAME_stand19 = 18;
        static const int FRAME_stand20 = 19;
        static const int FRAME_stand21 = 20;
        static const int FRAME_stand22 = 21;
        static const int FRAME_stand23 = 22;
        static const int FRAME_stand24 = 23;
        static const int FRAME_stand25 = 24;
        static const int FRAME_stand26 = 25;
        static const int FRAME_stand27 = 26;
        static const int FRAME_stand28 = 27;
        static const int FRAME_stand29 = 28;
        static const int FRAME_stand30 = 29;
        static const int FRAME_stand31 = 30;
        static const int FRAME_stand32 = 31;
        static const int FRAME_stand33 = 32;
        static const int FRAME_stand34 = 33;
        static const int FRAME_stand35 = 34;
        static const int FRAME_stand36 = 35;
        static const int FRAME_stand37 = 36;
        static const int FRAME_stand38 = 37;
        static const int FRAME_stand39 = 38;
        static const int FRAME_stand40 = 39;
        static const int FRAME_run1 = 40;
        static const int FRAME_run2 = 41;
        static const int FRAME_run3 = 42;
        static const int FRAME_run4 = 43;
        static const int FRAME_run5 = 44;
        static const int FRAME_run6 = 45;
        static const int FRAME_attack1 = 46;
        static const int FRAME_attack2 = 47;
        static const int FRAME_attack3 = 48;
        static const int FRAME_attack4 = 49;
        static const int FRAME_attack5 = 50;
        static const int FRAME_attack6 = 51;
        static const int FRAME_attack7 = 52;
        static const int FRAME_attack8 = 53;
        static const int FRAME_pain101 = 54;
        static const int FRAME_pain102 = 55;
        static const int FRAME_pain103 = 56;
        static const int FRAME_pain104 = 57;
        static const int FRAME_pain201 = 58;
        static const int FRAME_pain202 = 59;
        static const int FRAME_pain203 = 60;
        static const int FRAME_pain204 = 61;
        static const int FRAME_pain301 = 62;
        static const int FRAME_pain302 = 63;
        static const int FRAME_pain303 = 64;
        static const int FRAME_pain304 = 65;
        static const int FRAME_jump1 = 66;
        static const int FRAME_jump2 = 67;
        static const int FRAME_jump3 = 68;
        static const int FRAME_jump4 = 69;
        static const int FRAME_jump5 = 70;
        static const int FRAME_jump6 = 71;
        static const int FRAME_flip01 = 72;
        static const int FRAME_flip02 = 73;
        static const int FRAME_flip03 = 74;
        static const int FRAME_flip04 = 75;
        static const int FRAME_flip05 = 76;
        static const int FRAME_flip06 = 77;
        static const int FRAME_flip07 = 78;
        static const int FRAME_flip08 = 79;
        static const int FRAME_flip09 = 80;
        static const int FRAME_flip10 = 81;
        static const int FRAME_flip11 = 82;
        static const int FRAME_flip12 = 83;
        static const int FRAME_salute01 = 84;
        static const int FRAME_salute02 = 85;
        static const int FRAME_salute03 = 86;
        static const int FRAME_salute04 = 87;
        static const int FRAME_salute05 = 88;
        static const int FRAME_salute06 = 89;
        static const int FRAME_salute07 = 90;
        static const int FRAME_salute08 = 91;
        static const int FRAME_salute09 = 92;
        static const int FRAME_salute10 = 93;
        static const int FRAME_salute11 = 94;
        static const int FRAME_taunt01 = 95;
        static const int FRAME_taunt02 = 96;
        static const int FRAME_taunt03 = 97;
        static const int FRAME_taunt04 = 98;
        static const int FRAME_taunt05 = 99;
        static const int FRAME_taunt06 = 100;
        static const int FRAME_taunt07 = 101;
        static const int FRAME_taunt08 = 102;
        static const int FRAME_taunt09 = 103;
        static const int FRAME_taunt10 = 104;
        static const int FRAME_taunt11 = 105;
        static const int FRAME_taunt12 = 106;
        static const int FRAME_taunt13 = 107;
        static const int FRAME_taunt14 = 108;
        static const int FRAME_taunt15 = 109;
        static const int FRAME_taunt16 = 110;
        static const int FRAME_taunt17 = 111;
        static const int FRAME_wave01 = 112;
        static const int FRAME_wave02 = 113;
        static const int FRAME_wave03 = 114;
        static const int FRAME_wave04 = 115;
        static const int FRAME_wave05 = 116;
        static const int FRAME_wave06 = 117;
        static const int FRAME_wave07 = 118;
        static const int FRAME_wave08 = 119;
        static const int FRAME_wave09 = 120;
        static const int FRAME_wave10 = 121;
        static const int FRAME_wave11 = 122;
        static const int FRAME_point01 = 123;
        static const int FRAME_point02 = 124;
        static const int FRAME_point03 = 125;
        static const int FRAME_point04 = 126;
        static const int FRAME_point05 = 127;
        static const int FRAME_point06 = 128;
        static const int FRAME_point07 = 129;
        static const int FRAME_point08 = 130;
        static const int FRAME_point09 = 131;
        static const int FRAME_point10 = 132;
        static const int FRAME_point11 = 133;
        static const int FRAME_point12 = 134;
        static const int FRAME_crstnd01 = 135;
        static const int FRAME_crstnd02 = 136;
        static const int FRAME_crstnd03 = 137;
        static const int FRAME_crstnd04 = 138;
        static const int FRAME_crstnd05 = 139;
        static const int FRAME_crstnd06 = 140;
        static const int FRAME_crstnd07 = 141;
        static const int FRAME_crstnd08 = 142;
        static const int FRAME_crstnd09 = 143;
        static const int FRAME_crstnd10 = 144;
        static const int FRAME_crstnd11 = 145;
        static const int FRAME_crstnd12 = 146;
        static const int FRAME_crstnd13 = 147;
        static const int FRAME_crstnd14 = 148;
        static const int FRAME_crstnd15 = 149;
        static const int FRAME_crstnd16 = 150;
        static const int FRAME_crstnd17 = 151;
        static const int FRAME_crstnd18 = 152;
        static const int FRAME_crstnd19 = 153;
        static const int FRAME_crwalk1 = 154;
        static const int FRAME_crwalk2 = 155;
        static const int FRAME_crwalk3 = 156;
        static const int FRAME_crwalk4 = 157;
        static const int FRAME_crwalk5 = 158;
        static const int FRAME_crwalk6 = 159;
        static const int FRAME_crattak1 = 160;
        static const int FRAME_crattak2 = 161;
        static const int FRAME_crattak3 = 162;
        static const int FRAME_crattak4 = 163;
        static const int FRAME_crattak5 = 164;
        static const int FRAME_crattak6 = 165;
        static const int FRAME_crattak7 = 166;
        static const int FRAME_crattak8 = 167;
        static const int FRAME_crattak9 = 168;
        static const int FRAME_crpain1 = 169;
        static const int FRAME_crpain2 = 170;
        static const int FRAME_crpain3 = 171;
        static const int FRAME_crpain4 = 172;
        static const int FRAME_crdeath1 = 173;
        static const int FRAME_crdeath2 = 174;
        static const int FRAME_crdeath3 = 175;
        static const int FRAME_crdeath4 = 176;
        static const int FRAME_crdeath5 = 177;
        static const int FRAME_death101 = 178;
        static const int FRAME_death102 = 179;
        static const int FRAME_death103 = 180;
        static const int FRAME_death104 = 181;
        static const int FRAME_death105 = 182;
        static const int FRAME_death106 = 183;
        static const int FRAME_death201 = 184;
        static const int FRAME_death202 = 185;
        static const int FRAME_death203 = 186;
        static const int FRAME_death204 = 187;
        static const int FRAME_death205 = 188;
        static const int FRAME_death206 = 189;
        static const int FRAME_death301 = 190;
        static const int FRAME_death302 = 191;
        static const int FRAME_death303 = 192;
        static const int FRAME_death304 = 193;
        static const int FRAME_death305 = 194;
        static const int FRAME_death306 = 195;
        static const int FRAME_death307 = 196;
        static const int FRAME_death308 = 197;

        //protected:

        /**
         * utility method for use internally.
         * attempts to put the item at the indicated inventory position
         * inventory position is 1-dimensional along x axis, with integral
         * positions from 0 to NUM_INVENTORY_SLOTS-1, inclusive.
         * if inventoryPos is -1, the first available slot is selected
         */
        bool itemToInventory( class Item * item, int inventoryPos = -1 );
        
        static const unsigned int NUM_INVENTORY_SLOTS = 24;
        static const char * const STAT_NAMES[];
        static const char * const STAT_ABBREVS[];
        
        const static int MAX_STAT = 100;
        const static int MAX_HP   = 10000;
        const static int MAX_AC   = 100;

        inline short getMaxHPs() const { return _maxHPs; }
        inline short getCurHPs() const { return _curHPs; }
        inline short getEyeLevel() const { return _eyeLevel; }
        
        inline void setEyeLevel( short level ) { _eyeLevel = level; }

        inline unsigned short getGold() const { return _gold; }
        inline unsigned short getExp() const { return _exp; }
        inline unsigned short getExpValue() const { return _expValue; }
        inline unsigned char getSkillPoints() const { return _skillPoints; }

        inline unsigned char getAC() const { return _AC; }
        inline unsigned char getStat( enum CharacterStat stat ) const { return _stats[ stat ]; }
                
        inline unsigned int getAffectFlags() const { return _affectFlags; }

        virtual inline int getTotalWeight() const { return Entity::getTotalWeight() + _wornWeight; }
        inline int getWornWeight() const { return _wornWeight; }
        inline int getEncumberanceWeight() const { return _wornWeight + getContainedWeight(); }
        inline unsigned char getLevel() const { return _level; }
        
        inline class Entity * getTargetEntity() const { return _targetEntity; }
        inline void setTargetEntity( class Entity * ent ) { _targetEntity = ent; }

        inline const char * getWeaponModelName() const { return _weaponModelName; }
        inline const char * getWeaponSkinName() const { return _weaponSkinName; }
        inline const char * setWeaponModelName( const char * name ) { return setString( &_weaponModelName, name ); }
        inline const char * setWeaponSkinName( const char * name ) { return setString( &_weaponSkinName, name ); }

        /**
         * moves an item from inventory to equipment
         * returns false if the equipment slot is full, the item is invalid
         * or inappropriate, or an error occurs
         */
        bool equipItem( class Item * item, WornPosition pos );

        /**
         * moves an item from either inventory or existing equipment 
         * to equipment, moving the currently equipped
         * item to the inventory or another eq pos, if applicable.
         *
         * returns false if the item is invalid or inappropriate, or an error occurs
         *
         * if the target equipment pos is empty, this call is equivalent to equipITem()
         */
        bool reEquipItem( class Item * item, WornPosition pos );

        /**
         * move an item from equipment to inventory
         */
        bool unequipItem( class Item * item, int inventoryPos = -1 );
        
        void getInventorySlots( class Item * slots[ NUM_INVENTORY_SLOTS ] ) const;
        
        bool slideInventoryItem( class Item * item, int targetPos );
        
        class Item * getInventoryItemAt( int pos ) const;

        class Item * getEquippedItem( WornPosition pos ) const { return _eq[ pos ]; }

        inline unsigned int getLastFootstepTick() const { return _lastFootstepTick; }
        inline void setLastFootstepTick( unsigned int tick ) { _lastFootstepTick = tick; }
        inline unsigned int getFootstepTickMin() const { return _footstepTickMin; }
        
        void attack( class Entity * vict );
        void jump();

        virtual bool collideWith( class Entity * other, const float * normal, unsigned int tick );

        Character( const char * name, const char * alias );
        Character( class ProtoChar * proto );
        virtual ~Character();

        virtual bool think( unsigned int tick );
        virtual bool takeDamage( int type, int location, int amount );
};

class CharacterAffect {
        int _type;
        int _flags;
        int _duration;
};

#endif
