/**
 * @file World.h
 *
 * Simulation of the level and the entities within it.
 */

#ifndef WORLD_H
#define WORLD_H

#include "Entity.h"
#include "Game.h"
#include "Player.h"

#include "netcode.h"

#define WORLD_MAX_PLAYERS 8
#define WORLD_MAX_ENTITIES 1024
#define WORLD_MAX_ITEMS 128
#define WORLD_MAX_SPRITES (WORLD_MAX_ENTITIES + WORLD_MAX_ITEMS)
#define WORLD_ITEM_BASEID WORLD_MAX_ENTITIES // base index of items in the sprites array

extern player_t World_Players[WORLD_MAX_PLAYERS]; // Player 0 is always the local player
extern sprite_t World_Sprites[WORLD_MAX_SPRITES];

typedef void(*IterateObjFunc_t)(Obj_t *obj, void *data);

void World_Init(RPKFile *rpk);
void World_Destroy(void);

void World_OnNewGame(enum GameStartType type, int startDepth);
void World_QuitGame(void);
void World_OnLevelChange(int level);

void World_Tick(void);
void World_Update(float deltaTime);
void World_Render(Bmp_t *screen, float delta);

int World_NumPlayers(void);
int World_SpawnPlayer(int num, int entityId);
void World_PlayerButtonPress(int playerId, int button);
void World_AwardKillToPlayer(const Obj_t *playerEntity, int xpReward);
void World_OnPlayerDeath(Obj_t *playerEntity);

void World_SpriteFromEntity(Obj_t *entity, sprite_t *sprite);
/**
 * Creates a new object in the world
 *
 * @returns The object just created, or NULL if there is no more room for objects.
 */
Obj_t *World_NewObject(int type, float x, float y);

void World_RemoveObject(Obj_t *);

/**
 * @brief Iterates through every object in an area matching the given predicate.
 *
 * @param predicate Only call the callback function for object matching this predicate. Use OF_ALL to iterate every object.
 * @param callback Function to be called for each object iterated over.
 * @param bounds If not NULL, only objects intersecting this rectangle will be iterated over.
 * @param data Pointer to custom data that will be passed as an arugment to the callback function.
 */
void World_IterateObjects(enum ObjFlags predicate, IterateObjFunc_t callback, struct Rect *bounds, void *data);
void World_HitscanObjects(enum ObjFlags predicate, IterateObjFunc_t callback, const Obj_t *src, float dir, float maxDist, int maxHits, void *data);

Obj_t *World_GetNearestEnemyObj(int team, float x, float y);
Obj_t *World_GetNearestAllyObj(Obj_t *obj, int team, float x, float y);

bool World_CanUseLadderUp(player_t *player);
bool World_CanUseLadderDown(player_t *player);

/**
* Spawns an item object into the world
*/
void World_DropItem(Item_t item, float x, float y, float z, float angle);

void World_RandomizeGrass(void);

bool World_UseEntities(player_t *player);
void World_PickUpItems(player_t *player);

void World_PlayGlobalSound(int soundId);
void World_PlayTileSound(int x, int y, int soundId);
void World_PlayEntitySound(Obj_t *source, int soundId);
void World_SetTile(int x, int y, char tile);

#endif
