/*
Copyright (C) 1996-1997 Id Software, Inc.

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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

*/

#ifndef CLIENT_H
#define CLIENT_H

#include "model.h"
#include "net.h"
#include "pmove.h"
#include "protocol.h"
#include "render.h"
#include "sound.h"
#include "vid.h"
#include "wad.h"
#include "zone.h"

//
// client_state_t should hold all pieces of the client state
//

typedef struct {
    char name[16];
    qboolean failedload;	// the name isn't a valid skin
    cache_user_t cache;
} skin_t;

#define	MAX_DLIGHTS	32
typedef struct {
    int key;			// so entities can reuse same entry
    vec3_t origin;
    float radius;
    float die;			// stop lighting after this time
    float decay;		// drop this each second
    float minlight;		// don't add when contributing less
    const float *color;
} dlight_t;

typedef struct {
    int length;
    char map[MAX_STYLESTRING];
} lightstyle_t;

// player_state_t is the information needed by a player entity
// to do move prediction and to generate a drawable entity
typedef struct {
    int messagenum;		// all player's won't be updated each frame

    double state_time;		// not the same as the packet time,
    // because player commands come asyncronously
    usercmd_t command;		// last command for prediction

    vec3_t origin;
    vec3_t viewangles;		// only for demos, not from server
    vec3_t velocity;
    int weaponframe;

    int modelindex;
    int frame;
    int skinnum;
    int effects;

    int flags;			// dead, gib, etc

    qboolean onground;
    float waterjumptime;
    int oldbuttons;
} player_state_t;


#define	MAX_SCOREBOARDNAME 16
typedef struct player_info_s {
    int userid;
    char userinfo[MAX_INFO_STRING];

    // scoreboard information
    char name[MAX_SCOREBOARDNAME];
    float entertime;
    int frags;
    int ping;
    byte pl;

    // skin information
    byte topcolor;
    byte bottomcolor;
    byte _topcolor;
    byte _bottomcolor;

    int spectator;
    byte translations[VID_GRADES * 256];
    skin_t *skin;
} player_info_t;


typedef struct {
    // generated on client side
    usercmd_t cmd;		// cmd that generated the frame
    double senttime;		// time cmd was sent off
    int delta_sequence;		// sequence number to delta from,
    // -1 = full update

    // received from server
    double receivedtime;	// time message was received, or -1
    player_state_t playerstate[MAX_CLIENTS];	// message received that reflects
    // performing the usercmd
    packet_entities_t packet_entities;
    qboolean invalid;		// set if the packet_entities delta was invalid
} frame_t;


typedef struct {
    int destcolor[3];
    int percent;		// 0-256
} cshift_t;

#define	CSHIFT_CONTENTS	0
#define	CSHIFT_DAMAGE	1
#define	CSHIFT_BONUS	2
#define	CSHIFT_POWERUP	3

#define	NUM_CSHIFTS	4

#define	MAX_EFRAGS	512
#define	MAX_DEMOS	8
#define	MAX_DEMONAME	16

typedef enum {
    ca_disconnected,		// full screen console with no connection
    ca_demostart,		// starting up a demo
    ca_connected,		// netchan_t established, waiting for svc_serverdata
    ca_onserver,		// processing data lists, donwloading, etc
    ca_active			// everything is in, so frames can be rendered
} cactive_t;

typedef enum {
    dl_none,
    dl_model,
    dl_sound,
    dl_skin,
    dl_single
} dltype_t;			// download type

//
// the client_static_t structure is persistant through an arbitrary number
// of server connections
//
typedef struct {
// connection information
    cactive_t state;

// network stuff
    netchan_t netchan;

// private userinfo for sending to masterless servers
    char userinfo[MAX_INFO_STRING];

    char servername[MAX_OSPATH];	// name of server from original connect

    int qport;

    FILE *download;		// file transfer from server
    char downloadtempname[MAX_OSPATH];
    char downloadname[MAX_OSPATH];
    int downloadnumber;
    dltype_t downloadtype;
    int downloadpercent;

// demo loop control
    int demonum;		// -1 = don't play demos
    char demos[MAX_DEMOS][MAX_DEMONAME];	// when not playing

// demo recording info must be here, because record is started before
// entering a map (and clearing client_state_t)
    qboolean demorecording;
    qboolean demoplayback;
    qboolean timedemo;
    FILE *demofile;
    float td_lastframe;		// to meter out one message a frame
    int td_startframe;		// host_framecount at start
    float td_starttime;		// realtime at second frame of timedemo

    int challenge;

    float latency;		// rolling average
} client_static_t;

extern client_static_t cls;

//
// the client_state_t structure is wiped completely at every
// server signon
//
typedef struct {
    int servercount;		// server identification for prespawns

    char serverinfo[MAX_SERVERINFO_STRING];

    int parsecount;		// server message counter
    int validsequence;		// this is the sequence number of the last good
    // packetentity_t we got.  If this is 0, we can't
    // render a frame yet
    int movemessages;		// since connecting to this server
    // throw out the first couple, so the player
    // doesn't accidentally do something the
    // first frame

    int spectator;

    double last_ping_request;	// while showing scoreboard
    double last_servermessage;

// sentcmds[cl.netchan.outgoing_sequence & UPDATE_MASK] = cmd
    frame_t frames[UPDATE_BACKUP];

// information for local display
    int stats[MAX_CL_STATS];	// health, etc
    float item_gettime[32];	// cl.time of aquiring item, for blinking
    float faceanimtime;		// use anim frame if cl.time < this

    cshift_t cshifts[NUM_CSHIFTS];	// color shifts for damage, powerups
    cshift_t prev_cshifts[NUM_CSHIFTS];	// and content types

// the client maintains its own idea of view angles, which are
// sent to the server each frame.  And only reset at level change
// and teleport times
    vec3_t viewangles;

// the client simulates or interpolates movement to get these values
    double time;		// this is the time value that the client
				// is rendering at.  always <= realtime
    vec3_t simorg;
    vec3_t simvel;
    vec3_t simangles;

// pitch drifting vars
    float pitchvel;
    qboolean nodrift;
    float driftmove;
    double laststop;


    float crouch;		// local amount for smoothing stepups

    qboolean paused;		// send over by server

    float punchangle;		// temporar yview kick from weapon firing

    int intermission;		// don't change view angle, full screen, etc
    int completed_time;		// latched ffrom time at intermission start

//
// information that is static for the entire time connected to a server
//
    char model_name[MAX_MODELS][MAX_QPATH];
    char sound_name[MAX_SOUNDS][MAX_QPATH];

    model_t *model_precache[MAX_MODELS];
    sfx_t *sound_precache[MAX_SOUNDS];

    char levelname[40];		// for display on solo scoreboard
    int playernum;

// refresh related state
    brushmodel_t *worldmodel;	// cl_entitites[0].model
    efrag_t *free_efrags;
    int num_entities;		// stored bottom up in cl_entities array
    int num_statics;		// stored top down in cl_entities

    int cdtrack;		// cd audio

    entity_t viewent;		// weapon model

// all player information
    player_info_t players[MAX_CLIENTS];
} client_state_t;


//
// cvars
//
extern cvar_t cl_warncmd;
extern cvar_t cl_upspeed;
extern cvar_t cl_forwardspeed;
extern cvar_t cl_backspeed;
extern cvar_t cl_sidespeed;

extern cvar_t cl_movespeedkey;

extern cvar_t cl_yawspeed;
extern cvar_t cl_pitchspeed;

extern cvar_t cl_anglespeedkey;

extern cvar_t cl_run;

extern cvar_t cl_shownet;
extern cvar_t cl_sbar;
extern cvar_t cl_hudswap;

extern cvar_t cl_pitchdriftspeed;
extern cvar_t lookspring;
extern cvar_t lookstrafe;
extern cvar_t sensitivity;

extern cvar_t m_pitch;
extern cvar_t m_yaw;
extern cvar_t m_forward;
extern cvar_t m_side;

extern cvar_t cl_maxpitch;
extern cvar_t cl_minpitch;

extern cvar_t m_freelook;

extern cvar_t name;

extern cvar_t cl_predict_players;
extern cvar_t cl_predict_players2;
extern cvar_t cl_solid_players;

extern int cl_spikeindex, cl_playerindex, cl_flagindex;
extern int parsecountmod;
extern double parsecounttime;

entity_t *CL_NewTempEntity(void);

#define	MAX_STATIC_ENTITIES	128	// torches, etc

extern client_state_t cl;

// FIXME, allocate dynamically
extern entity_state_t cl_baselines[MAX_EDICTS];
extern efrag_t cl_efrags[MAX_EFRAGS];
extern entity_t cl_static_entities[MAX_STATIC_ENTITIES];
extern entity_t cl_player_entities[MAX_CLIENTS];
extern lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES];
extern dlight_t cl_dlights[MAX_DLIGHTS];

//=============================================================================


//
// cl_main
//

extern int host_hunklevel;              // FIXME: probably should be an internal thing

dlight_t *CL_AllocDlight(int key);

/* The standard dynamic light colors */
enum {
    DLIGHT_FLASH = 0,
    DLIGHT_BLUE = 1,
    DLIGHT_RED = 2,
    DLIGHT_PURPLE = 3
};
extern const float dl_colors[4][4]; /* Use enums to reference the colors */

void CL_DecayLights(void);
void CL_RunParticles(void);

void CL_AddCommands();
void CL_RegisterVariables();
void CL_Init();

void CL_EstablishConnection(char *host);

void CL_Disconnect(void);
void CL_Disconnect_f(void);
void CL_NextDemo(void);
qboolean CL_DemoBehind(void);

void CL_BeginServerConnect(void);

#define MAX_VISEDICTS 1024
extern int cl_numvisedicts;
extern entity_t *cl_visedicts[];
extern int cl_visedicts_framenum;

extern int fps_count;
extern int minimum_memory;
extern qboolean isDedicated;

//
// cl_input
//
typedef struct {
    int down[2];		// key nums holding it down
    int state;			// low bit is down state
} kbutton_t;

extern kbutton_t in_mlook;
extern kbutton_t in_strafe;
extern kbutton_t in_speed;

void CL_Input_AddCommands();
void CL_Input_RegisterVariables();

void CL_SendCmd(const physent_stack_t *pestack);

void CL_ParseTEnt(void);
void CL_UpdateTEnts(void);

void CL_ClearState(void);

int CL_ReadFromServer(void);
void CL_WriteToServer(usercmd_t *cmd);
void CL_BaseMove(usercmd_t *cmd);

//
// cl_demo.c
//
void CL_StopPlayback(void);
qboolean CL_GetMessage(void);
void CL_WriteDemoCmd(usercmd_t *pcmd);

void CL_Stop_f(void);
void CL_Record_f(void);
void CL_ReRecord_f(void);

void CL_PlayDemo_f(void);
void CL_TimeDemo_f(void);
void CL_Demo_Arg_f(struct stree_root *root, int argnum);

//
// cl_parse.c
//
#define NET_TIMINGS 256
#define NET_TIMINGSMASK 255
extern int packet_latency[NET_TIMINGS];
int CL_CalcNet(void);
void CL_ParseServerMessage(void);
qboolean CL_CheckOrDownloadFile(const char *filename);
qboolean CL_IsUploading(void);
void CL_NextUpload(void);
void CL_StartUpload(byte *data, int size);
void CL_StopUpload(void);

//
// view.c
//
void V_StartPitchDrift(void);
void V_StopPitchDrift(void);

void V_RenderView(void);
void V_UpdatePalette(void);
void V_Register(void);
void V_ParseDamage(void);
void V_SetContentsColor(int contents);
void V_CalcBlend(void);

//
// cl_tent
//
void CL_InitTEnts(void);
void CL_ClearTEnts(void);

//
// cl_ents.c
//
void CL_SetSolidPlayers(physent_stack_t *pestack, int playernum);
void CL_SetUpPlayerPrediction(const physent_stack_t *pestack, qboolean dopred);
void CL_EmitEntities(physent_stack_t *pestack);
void CL_ClearProjectiles(void);
void CL_ParseProjectiles(void);
void CL_ParsePacketEntities(qboolean delta);
void CL_SetSolidEntities(physent_stack_t *pestack);
void CL_ParsePlayerinfo(void);

//
// cl_pred.c
//
void CL_Predict_RegisterVariables();
void CL_PredictMove(physent_stack_t *pestack);
void CL_PredictUsercmd(const player_state_t *from, player_state_t *to,
		       const usercmd_t *cmd, const physent_stack_t *pestack,
		       qboolean spectator);

//
// cl_cam.c
//
#define CAM_NONE	0
#define CAM_TRACK	1

extern int autocam;
extern int spec_track;		// player# of who we are tracking

qboolean Cam_DrawViewModel(void);
qboolean Cam_DrawPlayer(int playernum);
void Cam_Track(usercmd_t *cmd, const physent_stack_t *pestack);
void Cam_FinishMove(usercmd_t *cmd);
void Cam_Reset(void);

void CL_Cam_RegisterVariables();

//
// skin.c
//

void Skin_Find(player_info_t *sc);
byte *Skin_Cache(skin_t *skin);
void Skin_Skins_f(void);
void Skin_AllSkins_f(void);
void Skin_NextDownload(void);

#define RSSHOT_WIDTH 320
#define RSSHOT_HEIGHT 200

#endif /* CLIENT_H */
