/**
 * @file netcode.h
 *
 * Multiplayer networking protocol
 */

#ifndef H_NETCODE
#define H_NETCODE

#include <stdint.h>

#include "Net.h"

#define NET_MAX_CLIENTS 7 // max players minus one (host player)
#define NET_MAX_USERNAME 31

enum
{
	SPRITE_LIGHT_NONE,	// Sprite doesn't glow
	SPRITE_LIGHT_STATIC,	// Glows, but doesn't move, reduces amount of lighting computations each frame
	SPRITE_LIGHT_DYNAMIC	// Glows and moves, needs light recomputed each frame
};

// A sprite is a local copy of an entity that is sent over the network, and is only used for rendering on the client.
typedef struct EntitySprite
{
	int16_t id; // negative numbers indicate entity is not present
	int16_t x, y, z; // stored as 8.8 fixed point numbers
	uint16_t sprite;
	uint16_t angle;
	uint8_t fx;
	uint8_t light;
} sprite_t;

// Fields that need to be updated for the player in addition to the sprite properties
struct PlayerUpdate
{
	int16_t health, maxHealth;
	int16_t mana, maxMana;
	uint8_t str, spd, def, vit, itl;
	uint8_t handSlot;
	int16_t itemCooldown;
	uint16_t statPoints;
	uint16_t level;
	uint16_t xp;
};

// Conversion between fixed point and floating point
#define TOFIXED(f) (uint16_t)((f) * (float)(1 << 8))
#define TOFLOAT(f) ((float)(f) / (float)(1 << 8))

// Convert a floating point angle in radians to or from a 16-bit angle
#define ANGLE2FIXED(a) ((uint16_t)((a) / (MATH_PI * 2.f) * UINT16_MAX))
#define ANGLE2FLOAT(a) ((float)(a) / UINT16_MAX * MATH_PI * 2.f)

enum PacketType
{
	/**** Sent and recieved by both client and server ****/

	NET_PACKET_DISCONNECT,		// Removes a player from the game, or tells clients the server has shut down

	/**** Sent from the client to the server ****/

	NET_PACKET_C2S_LOGIN,		// Requests connection to the server, sets username.
	NET_PACKET_C2S_INPUTCMD,	// Player's input for a given tick. 
								// Expected for every tick, since the server uses this packet to know the connection status of the client.
	NET_PACKET_C2S_BUTTONPRESS,	// Tells the server that an input button was pressed.
	NET_PACKET_C2S_GUIINTERACT,	// Tells the server to click on a part of the inventory gui

	/**** Broadcast from the server to all clients ****/
	NET_PACKET_S2C_CHANGELEVEL,	// Tells clients floor is changing
	NET_PACKET_S2C_TILEMAP,		// Data for all tiles in the level
	NET_PACKET_S2C_SETTILE,		// Change a single tile in the level
	NET_PACKET_S2C_ENTITIES,	// A list of entity updates
	NET_PACKET_S2C_STATUSMSG,	// Displays text at the bottom of the screen
	NET_PACKET_S2C_PLAYSOUND,	// Plays a sound effect without stereo panning
	NET_PACKET_S2C_PLAYSOUND3D,	// Plays a sound effect at a location
	NET_PACKET_S2C_PARTICLES,	// Adds particle effects at a specific location
	NET_PACKET_S2C_BOSSBAR,		// Updates the boss health bar
	NET_PACKET_S2C_COMPASSTARGET, // Sets the position or entity that the compass should point to

	/**** Sent from the server, different for each client ****/

	NET_PACKET_S2C_SETPLAYER,	// Tells the client which entity is the player, must be acked before client can join game.
	NET_PACKET_S2C_PLAYERSTATE,	// Updates player health, stats, xp etc.
	NET_PACKET_S2C_INVENTORY,	// Updates slots in the inventory
};

struct PacketHeader
{
	uint16_t type;		// Type of packet
	uint16_t size;		// Number of bytes of extra data
	uint32_t tick;		// The tick number that this packet's data pertains to
	uint32_t timestamp; // Timestamp in ms that this packet was sent
	uint32_t seqnum;	// Sequence number of this packet
	uint32_t acknum;	// The last recieved sequence number in this connection
};

enum ClientState
{
	// No one is connected to this client slot.
	NET_CLIENT_NONE,
	// Client is connected, but hasn't recieved the level, entities, or player yet.
	NET_CLIENT_CONNECTED,
	// Client is fully connected, and has loaded into the game world.
	NET_CLIENT_LOADED,
};

// Client as it is seen by the server
typedef struct Client
{
	enum ClientState state;
	Netaddr address;
	short entityId;
	int seqnum;	// Sequence number of this channel between client and server
	int ack;
} client_t;

// Client-side
void Netcode_Cl_Init(void);
void Netcode_Cl_Close(void);
void Netcode_Cl_ReadPackets(void);
void Netcode_Cl_Tick(void);

void Netcode_Cl_SendButton(int button);
void Netcode_Cl_GuiInteract(int interact);

// Server-side
void Netcode_Sv_Init(void);
void Netcode_Sv_Close(void);
void Netcode_Sv_ReadPackets(void);
void Netcode_Sv_Tick(void);

void Netcode_Sv_PlaySound(int id);
void Netcode_Sv_PlaySound3D(int soundId, int entityId, float x, float y, float dx, float dy);
void Netcode_Sv_SetTile(int x, int y, char tile);
void Netcode_Sv_ChangeLevel(int depth);

#endif
