/*
 * This is the main headerfile
 */

#ifndef MUD_H
#define MUD_H

#include <zlib.h>
#include <pthread.h>
#include <arpa/telnet.h>

/* Mud_name: Global basic name of the mud
 * called in several locations, like who, login
 * screen, login infos, etc
 */
#define MUD_NAME        "The world of Geshia"

#include "lang.h"       /* Language File */

/************************
 * Standard definitions *
 ************************/

/* define TRUE and FALSE */
#ifndef FALSE
#define FALSE   0
#endif
#ifndef TRUE
#define TRUE    1
#endif

#define eTHIN   0
#define eBOLD   1

/* A few globals */
#define PULSES_PER_SECOND       5                   /* must divide 1000 : 4, 5 or 8 works */
#define MAX_BUFFER          32768                   /* seems like a decent amount         */
#define MAX_OUTPUT          32768                   /* well shoot me if it isn't enough   */
#define MAX_HELP_ENTRY      32768                   /* roughly 40 lines of blocktext      */
#define MUDPORT             9009                    /* just set whatever port you want    */
#define FILE_TERMINATOR     "EOF"                   /* end of file marker                 */
#define EXE_FILE            "../src/SocketMud"      /* the name of the mud binary         */
#define DEFAULT_TITLE       "the guest"             /* Default title                      */
#define END_MARKER          "END"                   /* End marker for data files          */
/*
 * Data Files
 */
#define TIME_FILE           "../data/time.txt"      /* The time file                      */
#define COPYOVER_FILE       "../txt/copyover.dat"   /* tempfile to store copyover data   */
#define AREA_FILE           "../data/areas.txt"
#define NOTE_FILE           "../data/notes.txt"
#define NULL_FILE           "/dev/null"
#define CHANGE2_FILE        "../help/changes.txt"
extern  FILE    *   fpReserve;

/* Connection states */
#define STATE_NEW_NAME         0
#define STATE_NEW_PASSWORD     1
#define STATE_VERIFY_PASSWORD  2
#define STATE_ASK_PASSWORD     3
#define STATE_PLAYING          4
#define STATE_CLOSED           5

/* Thread states - please do not change the order of these states    */
#define TSTATE_LOOKUP          0  /* Socket is in host_lookup        */
#define TSTATE_DONE            1  /* The lookup is done.             */
#define TSTATE_WAIT            2  /* Closed while in thread.         */
#define TSTATE_CLOSED          3  /* Closed, ready to be recycled.   */

/* player levels */
#define LEVEL_GUEST            1  /* Dead players and actual guests  */
#define LEVEL_PLAYER           2  /* Almost everyone is this level   */
#define LEVEL_ADMIN            3  /* Any admin without shell access  */
#define LEVEL_GOD              4  /* Any admin with shell access     */

/* Communication Ranges */
#define COMM_LOCAL             0  /* same room only                  */
#define COMM_CHAT              1  /* Global Chanel                   */
#define COMM_LOG              10  /* admins only                     */

/* define simple types */
typedef  unsigned char     bool;
typedef  short int         sh_int;


/******************************
 * End of standard definitons *
 ******************************/

/***********************
 * Defintion of Macros *
 ***********************/

#define UMIN(a, b)		((a) < (b) ? (a) : (b))
#define LOWER(c)        ((c) >= 'A' && (c) <= 'Z' ? (c)+'a'-'A' : (c))
#define UPPER(c)        ((c) >= 'a' && (c) <= 'z' ? (c)+'A'-'a' : (c))
#define IS_ADMIN(dMob)          ((dMob->level) > LEVEL_PLAYER ? TRUE : FALSE)
#define IREAD(sKey, sPtr)             \
{                                     \
  if (compares(sKey, word))           \
  {                                   \
    int sValue = fread_number(fp);    \
    sPtr = sValue;                    \
    found = TRUE;                     \
    break;                            \
  }                                   \
}
#define SREAD(sKey, sPtr)             \
{                                     \
  if (compares(sKey, word))           \
  {                                   \
    sPtr = fread_string(fp);          \
    found = TRUE;                     \
    break;                            \
  }                                   \
}
/*
 * Reads a Knowledge string from file
 */
#define KREAD(sKey, dMob)                   \
{                                           \
    if (compares(sKey, word))               \
    {                                       \
        int value   = fread_number(fp);     \
        char * temp = fread_word(fp);       \
        int sn      = find_knowledge(temp); \
        if (sn < 0)                         \
        {                                   \
            log_string("load_player: KREAD unknown knowledge %s", temp); \
        }                                   \
        else                                \
            dMob->knowledge[sn] = value;    \
        found = TRUE;                       \
        break;                              \
    }                                       \
}
/*
 * LREAD()
 * reads a Skill from file
 */
#define LREAD(sKey, dMob)                   \
{                                           \
    if (compares(sKey, word))               \
    {                                       \
        int value   = fread_number(fp);     \
        char * temp = fread_word(fp);       \
        int sn      = find_skill(temp);     \
        if (sn < 0)                         \
        {                                   \
            log_string("load_player: LREAD unknown skill %s", temp); \
            log_string("load_player: LREAD unknown skill %s", temp); \
        }                                   \
        else                                \
            dMob->skills[sn] = value;       \
        found = TRUE;                       \
        break;                              \
    }                                       \
}
/*
 * TREAD()
 * reads a Knowledge from file
 */
#define TREAD(sKey, dMob)                   \
{                                           \
    if (compares(sKey, word))               \
    {                                       \
        int value   = fread_number(fp);     \
        char * temp = fread_word(fp);       \
        int sn      = find_talent(temp); \
        if (sn < 0)                         \
        {                                   \
            log_string("load_player: TREAD unknown Talent %s", temp); \
        }                                   \
        else                                \
            dMob->talents[sn] = value;      \
        found = TRUE;                       \
        break;                              \
    }                                       \
}
/*
 * AREAD()
 * Reads an Attribute from File
 */
#define AREAD(sKey, dMob)                   \
{                                           \
    if (compares(sKey, "Attribs"))          \
    {                                       \
        dMob->attribs[0] = fread_number(fp);\
        dMob->attribs[1] = fread_number(fp);\
        dMob->attribs[2] = fread_number(fp);\
        dMob->attribs[3] = fread_number(fp);\
        dMob->attribs[4] = fread_number(fp);\
        dMob->attribs[5] = fread_number(fp);\
        dMob->attribs[6] = fread_number(fp);\
        dMob->attribs[7] = fread_number(fp);\
        found = TRUE;                       \
    break;                                  \
    }                                       \
}
/*
 * BREAD()
 * Reads an Attribute_max from File
 */
#define BREAD(sKey, dMob)                   \
{                                           \
    if (compares(sKey, "Attribs_max"))      \
    {                                       \
        dMob->attribs_max[0] = fread_number(fp);\
        dMob->attribs_max[1] = fread_number(fp);\
        dMob->attribs_max[2] = fread_number(fp);\
        dMob->attribs_max[3] = fread_number(fp);\
        dMob->attribs_max[4] = fread_number(fp);\
        dMob->attribs_max[5] = fread_number(fp);\
        dMob->attribs_max[6] = fread_number(fp);\
        dMob->attribs_max[7] = fread_number(fp);\
        found = TRUE;                       \
    break;                                  \
    }                                       \
}
/* VREAD()
 * Reads Vitals from a file */
#define VREAD(sKey, dMob)                   \
{                                           \
    if (compares(sKey, "HpMaStEg"))         \
    {                                       \
        dMob->stats[0] = fread_number(fp);  \
        dMob->stats[1] = fread_number(fp);  \
        dMob->stats[2] = fread_number(fp);  \
        dMob->stats[3] = fread_number(fp);  \
        dMob->stats[4] = fread_number(fp);  \
        dMob->stats[5] = fread_number(fp);  \
        dMob->stats[6] = fread_number(fp);  \
        dMob->stats[7] = fread_number(fp);  \
        found = TRUE;                       \
        break;                              \
    }                                       \
}

/* EREAD()
 * Reads EOF from file */
#define EREAD(sKey)                         \
{                                           \
    if (compares(word, "EOF"))              \
    {                                       \
        done = TRUE;                        \
        found = TRUE;                       \
        break;                              \
    }                                       \
}


/***********************
 * End of Macros       *
 ***********************/

/******************************
 * Bit flag Support           *
 ******************************/
#define IS_SET(flag, bit)       ((flag) & (bit))
#define SET_BIT(var, bit)       ((var) |= (bit))
#define REMOVE_BIT(var, bit)    ((var) &= ~(bit))
#define TOGGLE_BIT(var, bit)    ((var) ^= (bit))
/* Easy reading */
#define A                       0x1
#define B                       0x2
#define C                       0x4
#define D                       0x8
#define E                       0x10
#define F                       0x20
#define G                       0x40
#define H                       0x80
#define I                       0x100
#define J                       0x200
#define K                       0x400
#define L                       0x800
#define M                       0x1000
#define N                       0x2000
#define O                       0x4000
#define P                       0x8000
#define Q                       0x10000
#define R                       0x20000
#define S                       0x40000
#define T                       0x80000
#define U                       0x100000
#define V                       0x200000
#define W                       0x400000
#define X                       0x800000
#define Y                       0x1000000
#define Z                       0x2000000
/* I honestly wont need all 26, i dont think at least, besides was too lazy to finish it*/

/******************************
 * New structures             *
 ******************************/

/* type defintions */
typedef struct  dSocket       D_SOCKET;
typedef struct  dMobile       D_MOBILE;
typedef struct  help_data     HELP_DATA;
typedef struct  lookup_data   LOOKUP_DATA;
    
/* Moved up here for strange mud.h i have going here */
#define  D_S         D_SOCKET
#define  D_M         D_MOBILE

/* Universal Includes */
#include "locations.h"      /* AREA_DATA stuff */
#include "justify.h"        /* Justification snippet from Richard Woolcock aka KaVir */
#include "random.h"         /* Random Number generator */
#include "movement.h"       /* Stuff for movement */
#include "world.h"          /* Load/save World data */
#include "note.h"           /* Note data */
#include "player.h"         /* Player stuff */
#include "list.h"           /* Jobo's Generic Linked List API */
#include "mobile.h"         /* Mobile Stuff */

/* the actual structures */
struct dSocket
{
  D_SOCKET      * next;
  D_MOBILE      * player;
  char          * hostname;
  char            inbuf[MAX_BUFFER];
  char            outbuf[MAX_OUTPUT];
  char            next_command[MAX_BUFFER];
  bool            bust_prompt;
  sh_int          lookup_status;
  sh_int          state;
  sh_int          control;
  sh_int          top_output;
  unsigned char   compressing;                 /* MCCP support */
  z_stream      * out_compress;                /* MCCP support */
  unsigned char * out_compress_buf;            /* MCCP support */
};

struct dMobile
{
    D_MOBILE      * next;
    D_SOCKET      * socket;
    char          * name;                   /* Player's Name                */
    char          * password;               /* Players Passwd               */
    bool            is_npc;                 /* True if NPC                  */
    sh_int          level;                  /* Admin game level             */
    sh_int          p_level;                /* Player's In-game Level       */
    sh_int          x;                      /* World Map Location X         */
    sh_int          y;                      /* World Map Location Y         */
    sh_int          z;                      /* World Map Location Z         */
    int             i_x;                    /* Chunk location X             */
    int             i_y;                    /* Chunk location Y             */
    long            immortal_flags;         /* Immortal Flags               */
    long            player_flags;           /* Player Flags                 */
    sh_int          view_x;                 /* Max view distance X          */
    sh_int          view_y;                 /* Max view distance Y          */
    char          * title;                  /* Title of the Player          */
    NOTE_DATA     * in_progress;            /* Note currently in progress   */
    sh_int          stats[MAX_STATS];       /* Player's Statistics HpMaStFt */
    sh_int          attribs[MAX_ATTRIBS];   /* Player Attributes            */
    sh_int          attribs_max[MAX_ATTRIBS];/* Max Player Attributes       */
    sh_int          talents[MAX_TALENTS];   /* Player's Talents             */
    sh_int          skills[MAX_SKILLS];     /* Player's Skills              */
    sh_int          knowledge[MAX_KNOW];    /* Player's Knowledges          */
    sh_int          talents_t[MAX_TALENTS]; /* Player's Talents             */
    sh_int          skills_t[MAX_SKILLS];   /* Player's Skills              */
    sh_int          knowledge_t[MAX_KNOW];  /* Player's Knowledges          */
    sh_int          race;                   /* Player's Race                */
    sh_int          class;                  /* Player's Class               */
    sh_int          age;                    /* Player's Age                 */
    sh_int          xp;                     /* Player's XP, or Mobiles Value*/
};

struct help_data
{
  HELP_DATA     * next;
  time_t          load_time;
  char          * keyword;
  char          * text;
};

struct lookup_data
{
  D_SOCKET       * dsock;   /* the socket we wish to do a hostlookup on */
  char           * buf;     /* the buffer it should be stored in        */
};

struct typCmd
{
  char      * cmd_name;
  void     (* cmd_funct)(D_MOBILE *dMOb, char *arg);
  sh_int      level;
};

typedef struct buffer_type
{
  char   * data;        /* The data                      */
  int      len;         /* The current len of the buffer */
  int      size;        /* The allocated size of data    */
} BUFFER;

/******************************
 * End of new structures      *
 ******************************/

/***************************
 * System Flags            *
 ***************************/
#define SYS_IS_MOBILE       A       /* Is a mobile */


/***************************
 * Player Flags            *
 ***************************/
 
#define PLR_CLEAR_SCREEN    A       /* Clear screen on look */
#define PLR_INFO_LOGIN      B       /* Display Logins       */
#define PLR_INFO_LOGOUT     C       /* Display Logouts      */

/***************************
 * Immortal Flags          *
 ***************************/
#define IMMORTAL_OMNI_VIEW  A       /* Bypass view block    */
#define IMMORTAL_PASS_DOOR  B       /* Bypass terrain       */

/***************************
 * Global Variables        *
 ***************************/

extern  D_SOCKET    *   dsock_free;       /* the socket free list               */
extern  D_SOCKET    *   dsock_list;       /* the linked list of active sockets  */
extern  D_MOBILE    *   dmobile_free;     /* the mobile free list               */
extern  D_MOBILE    *   dmobile_list;     /* the mobile list of active mobiles  */
extern  HELP_DATA   *   help_list;        /* the linked list of help files      */
extern  const struct    typCmd tabCmd[];  /* the command table                  */
extern  bool            shut_down;        /* used for shutdown                  */
extern  char        *   greeting;         /* the welcome greeting               */
extern  char        *   motd;             /* the MOTD help file                 */
extern  int             control;          /* boot control socket thingy         */
extern  time_t          current_time;     /* let's cut down on calls to time()  */

/*************************** 
 * End of Global Variables *
 ***************************/

/***********************
 *    MCCP support     *
 ***********************/

extern const unsigned char compress_will[];
extern const unsigned char compress_will2[];

#define TELOPT_COMPRESS       85
#define TELOPT_COMPRESS2      86
#define COMPRESS_BUF_SIZE   8192

/***********************
 * End of MCCP support *
 ***********************/

/***********************************
 * Prototype function declerations *
 ***********************************/
#define  buffer_new(size)             __buffer_new     ( size)
#define  buffer_strcat(buffer,text)   __buffer_strcat  ( buffer, text )

char  *crypt                  ( const char *key, const char *salt );

/*
 * socket.c
 */
int   init_socket             ( void );
bool  new_socket              ( int sock );
void  close_socket            ( D_S *dsock, bool reconnect );
bool  read_from_socket        ( D_S *dsock );
bool  text_to_socket          ( D_S *dsock, const char *txt );  /* sends the output directly */
void  text_to_buffer          ( D_S *dsock, const char *txt );  /* buffers the output        */
void  text_to_mobile          ( D_M *dMob, const char *txt );   /* buffers the output        */
void  next_cmd_from_buffer    ( D_S *dsock );
bool  flush_output            ( D_S *dsock );
void  handle_new_connections  ( D_S *dsock, char *arg );
void  clear_socket            ( D_S *sock_new, int sock );
void  recycle_sockets         ( void );
void *lookup_address          ( void *arg );
void  send_to_char            ( const char *txt, D_M *dMob );
#define stc send_to_char

/*
 * interpret.c
 */
void    handle_cmd_input        ( D_S *dsock, char *arg );
bool    is_number               (char *arg);
char  * one_argument            (char *argument, char *arg_first);

/*
 * io.c
 */
void    log_string            ( const char *txt, ... );
void    bug                   ( const char *txt, ... );
time_t  last_modified         ( char *helpfile );
char   *read_help_entry       ( const char *helpfile );     /* pointer         */
char   *fread_line            ( FILE *fp );                 /* pointer         */
char   *fread_string          ( FILE *fp );                 /* allocated data  */
char   *fread_word            ( FILE *fp );                 /* pointer         */
int     fread_number          ( FILE *fp );                 /* just an integer */

/* 
 * strings.c
 */
char   *one_arg               ( char *fStr, char *bStr );
bool    compares              ( const char *aStr, const char *bStr );
bool    is_prefix             ( const char *aStr, const char *bStr );
char   *capitalize            ( char *txt );
BUFFER *__buffer_new          ( int size );
void    __buffer_strcat       ( BUFFER *buffer, const char *text );
void    buffer_free           ( BUFFER *buffer );
void    buffer_clear          ( BUFFER *buffer );
int     bprintf               ( BUFFER *buffer, char *fmt, ... );

/*
 * update.c
 */
#define PULSE_PER_SECOND    4
#define PULSE_WORLD         (600 * PULSE_PER_SECOND)
#define PULSE_DOORS         (60 * PULSE_PER_SECOND)
void    update_handler      ( void );
void    update_weather      ( void );
void    close_doors         ( void );
void    save_time           ( void );
void    load_time           ( void );

#define SUN_RISE    1
#define SUN_LIGHT   2
#define SUN_HIGH    3
#define SUN_SETTING 4
#define SUN_DARK    4

void cmd_time       (D_M * ch, char *arg);
typedef struct  time_data_data      TIME_INFO_DATA;
extern          TIME_INFO_DATA      time_data;
struct time_data_data
{
    int hour;       /* Hour of the day  */
    int day;        /* Day of the week  */
    int week;       /* Week of the month*/
    int month;      /* Month of year    */
    int year;       /* The year         */
    /* End dates, begin extras */
    int sunlight;   /* How much sunlight*/
};

/*
 * help.c
 */
bool  check_help              ( D_M *dMob, char *helpfile );
void  load_helps              ( void );
void  add_help                ( HELP_DATA *help );

/*
 * utils.c
 */
bool    check_name              ( const char *name );
void    clear_mobile            ( D_M *dMob );
void    free_mobile             ( D_M *dMob );
void    ex_free_mob             ( D_MOBILE * dMob );
void    communicate             ( D_M *dMob, char *txt, int range );
void    mudwide_info            (char * txt);
void    load_muddata            ( bool fCopyOver );
char  * get_time                ( void );
void    copyover_recover        ( void );
D_M   * check_reconnect         ( char *player );
D_M   * get_dmob_world          (D_MOBILE * dMob, char *name);
bool    is_name                 (char *str, char *namelist);
bool    str_prefix              (const char *astr, const char *bstr);
void    smash_space             (char *str);
void    smash_tidle             (char *str);
/*
 * action_safe.c
 */
void    cmd_say                 ( D_M *dMob, char *arg );
void    cmd_chat                ( D_M *dMob, char *arg );
void    cmd_quit                ( D_M *dMob, char *arg );
void    cmd_shutdown            ( D_M *dMob, char *arg );
void    cmd_commands            ( D_M *dMob, char *arg );
void    cmd_who                 ( D_M *dMob, char *arg );
void    cmd_help                ( D_M *dMob, char *arg );
void    cmd_compress            ( D_M *dMob, char *arg );
void    cmd_save                ( D_M *dMob, char *arg );
void    cmd_copyover            ( D_M *dMob, char *arg );
void    cmd_linkdead            ( D_M *dMob, char *arg );
void    cmd_location            ( D_M * ch,  char *arg );
void    cmd_number_here         (D_MOBILE * ch, char * arg);
void    cmd_recall              (D_MOBILE * ch, char * arg);
char    *return_who_level_name  (D_M * ch);
void cmd_test2   (D_MOBILE * ch, char *arg);

/* act_player.c */
void    cmd_title               (D_M * ch, char *arg);
void    cmd_config              (D_MOBILE * ch, char * arg);
char  * return_setting          (D_M * ch, long bit);
void    toggle_clear_screen     (D_M * ch);
void    toggle_logout           (D_M * ch);
void    toggle_login            (D_M * ch);
void    cmd_score               (D_MOBILE * ch, char *arg);
void    cmd_skills              (D_M * ch, char *arg);
char  * score_dots              (int number);
/* builder.c */
void    cmd_edit_box            (D_MOBILE * ch, char * arg);

/* act_imm.c */
void cmd_echo                   (D_M * ch, char * arg);
void cmd_display_bits           (D_M * ch, char * arg);
void cmd_omni_view              (D_M * ch, char * arg);
void cmd_pass_door              (D_M * ch, char * arg);
void cmd_advance                (D_M * ch, char * arg);
void cmd_pset                   (D_M * ch, char * arg);
/*
 * mccp.c
 */
bool  compressStart           ( D_S *dsock, unsigned char teleopt );
bool  compressEnd             ( D_S *dsock, unsigned char teleopt, bool forced );

/*
 * save.c
 */
void  save_player             ( D_M *dMob );
D_M  *load_player             ( char *player );
D_M  *load_profile            ( char *player );

void tail();

/*******************************
 * End of prototype declartion *
 *******************************/

#define MAX_CHANGE  25
#define CHANGE_FILE "../data/changes.txt"
typedef struct  change_data             CHANGE_DATA;

struct change_data
{
  CHANGE_DATA *next;
  CHANGE_DATA *prev;
  char        *imm;
  char        *text;
  char        *date;
};

void do_delchange   (D_MOBILE *ch, char *argument);
void do_changes(D_MOBILE *ch, char *argument);
void do_addchange( D_MOBILE *ch, char *argument );
void cmd_clearchanges (D_MOBILE * ch, char *arg);
#endif  /* MUD_H */