/*
  File name: GameControl.h
  Copyright: (C) 2004 - 2008 Tomasz Kazmierczak

  Creation date: 08.05.2004
  Last modification date: 30.12.2008

  This file is part of Cytadela

 *   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 3 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, see <http://www.gnu.org/licenses/>.  *

*/

#ifndef _GAMECTRL_H_
#define _GAMECTRL_H_

#include <stdint.h>
#include "cmf/GameObjectsManager.h"
#include "cmf/Enemy.h"
#include "COGLClass.h"
#include "CSDLClass.h"
#include "CInfoText.h"
#include "Localization.h"
#include "CCytadelaConfig.h"
#include "UsableItem.h"

//'double' data type is not used, so define float mathematical constants
#define ANG_PI2       1.5707963f
#define ANG_PI        3.1415927f
#define ANG_32PI      4.7123890f
#define ANG_2PI       6.2831853f

#define ANG_45DEG     0.7853982f
#define ANG_135DEG    2.3561945f
#define ANG_225DEG    3.9269908f
#define ANG_315DEG    5.4977871f

#define SQR2BY2       0.7071068f

#define SLOT_RED               1
#define SLOT_GREEN             2
#define SLOT_BLUE              3
#define SLOT_USED              4
#define SLOT_DISABLED          5

#define EQ_HANDGUN          0x02
#define EQ_SHOTGUN          0x03
#define EQ_MACHINEGUN       0x04
#define EQ_FLAMETHROWER     0x05
#define EQ_BLASTER          0x06
#define EQ_ROCKETLAUNCHER   0x07
#define EQ_HANDGUN_A        0x08
#define EQ_SHOTGUN_A        0x09
#define EQ_MACHINEGUN_A     0x0A
#define EQ_FLAMETHROWER_A   0x0B
#define EQ_BLASTER_A        0x0C
#define EQ_ROCKETLAUNCHER_A 0x0D
#define EQ_RED_CARD         0x0E
#define EQ_GREEN_CARD       0x0F
#define EQ_BLUE_CARD        0x10
#define EQ_MEDIPACK         0x11
#define EQ_SYRINGE          0x12
#define EQ_BEER             0x13
#define EQ_BOMB             0x14

#define ANIM_FORWARD           1
#define ANIM_STOP              0
#define ANIM_BACKWARD         -1

enum {
	CSND_WALL_BUMP,
	CSND_PLAYER_HIT,
	CSND_TOUCH_FLAMES,
	CSND_EXPLOSION,
	CSND_NUM_SOUNDS
};

enum {
	ESND_DEATH,
	ESND_ROAR1,
	ESND_ROAR2,
	ESND_ROAR3,
	ESND_FIRE,
	ESND_NUM_SOUNDS
};

enum {
	WSND_HANDGUN,
	WSND_SHOTGUN,
	WSND_MASHINEGUN,
	WSND_FLAMER,
	WSND_BLASTER,
	WSND_ROCKETLAUNCHER,
	WSND_NUM_SOUNDS
};

typedef enum {
	EXPLT_SMALL,
	EXPLT_BIG,
	EXPLT_ELECTRIC
} ExplosionType;

typedef enum {
	VOLDIST_TYPE1,
	VOLDIST_TYPE2,
	VOLDIST_TYPE3
} VolumeCalculationMethod;

typedef union {
	int32_t i;
	float f;
} intfloat;

class UpdateData {
public:
	float    *x;
	float    *z;
	float     dirX;
	float     dirZ;
	float     rotY;
	uint32_t  miliseconds;
	int32_t   takenItem;
	uint32_t  teleportationTime;
	uint16_t  lostEnergy;
	uint8_t  *position;
};

typedef std::list<TemporaryObject *> TempObjList;
typedef std::list<Enemy *> EnemiesList;
typedef std::map<UsableItemType, Weapon> WeaponsMap;

class GameControl {
private:
	GameObjectsManager     *mObjects;
	COGLClass       *mOGL;
	CSDLClass       *mSDL;
	CInfoText       *mTexts;
	Localization    *mLocInterface;
	CCytadelaConfig *mConfig;
	Vector3Dg        mPrevCamPosition;
	Vector3Dg        mCameraPosition;
	Vector3Dg        mCameraDirection;
	Vector3Dg        mVelocity;
	Vector3Dg        mAuxiliaryV;
	Point3Dg         mCameraAngles;
	TempObjList      mTempObjects;
	EnemiesList      mEnemies;
	MeshBase3Dg     *mSmallExplosionBase;
	MeshBase3Dg     *mBigExplosionBase;
	MeshBase3Dg     *mEquipmentBase;
	uint32_t         mMiliseconds;
	int32_t          mAuxVTime;
	uint32_t         mRocketLoadTime;
	uint32_t         mMGFireDiff;
	uint32_t         mPlayerBurnDiff;
	uint32_t         mLastRoarTime;
	float            mCamRay;
	float            mEnemyRay;
	uint8_t          mPosition[2];
	uint8_t          mPrevPosition[2];
	MapDataPtr       mLevelMap;
	float            mHeartBeat;
	uint16_t         mLostEnergy;
	float            mSinCameraRotation;
	float            mCosCameraRotation;

	//items collisions
	void handCollision(UsableItem *hand);
	bool cardCollision(UsableItemType cardColor);
	//ammo collisions
	float wallCollisionAmmo(Vector3Dg &begin, Vector3Dg &end, uint8_t xpos, uint8_t zpos,
	                        uint32_t walldir, GameObject *obj);
	float spriteCollisionAmmo(Vector3Dg &begin, Vector3Dg &end, uint8_t xpos, uint8_t zpos, float range);
	float enemyCollisionAmmo(Vector3Dg &begin, Vector3Dg &end, Vector3Dg &enemypos, float range);
	void ammoCollision(Weapon *weapon, Vector3Dg position, Vector3Dg direction);
	bool bulletCollision(Weapon *weapon, float range, Vector3Dg position, Vector3Dg direction,  Vector3Dg &origin);
	void explosionCollision(Vector3Dg &position);
	float playerCollisionAmmo(Vector3Dg &begin, Vector3Dg &end, float range);
	void fireAmmo(Weapon *weapon, Vector3Dg position, Vector3Dg direction);
	bool bulletEdgesCollision(bool *edges, Vector3Dg &begin, Vector3Dg &end, int8_t x, int8_t z, float edgeRay, Vector3Dg &destination);
	//player collisions
	bool spriteCollision(Mesh3Dg *mesh);
	uint16_t enemyCollision();
	uint16_t wallCollision(GameObject *obj, int8_t wallDir);
	void edgesCollision(bool *edges);
	void openDoor(uint32_t meshNum, GODoor *door);
	void animDoorOpen(GODoor *door, uint32_t doorType);
	void animDoorClose(GODoor *door, uint32_t doorType);
	//enemy collisions
	void enemyWallCollision(Enemy *enemy, Mesh3Dg *wallMesh, int8_t wallDir, float ray);
	void enemyBackWallCollision(Enemy *enemy, Mesh3Dg *wallMesh, int8_t wallDir, float ray);
	bool enemyObjectCollision(Vector3Dg &objPos, Enemy *enemy, float collisionDistance);
	void enemyCollision(Enemy *enemyToCheck);
	void enemyEdgesCollision(bool *edges, Enemy *enemy, int8_t x, int8_t z, float ray);

	void playerHit(uint16_t lostHP, Vector3Dg direction = Vector3Dg());
	void excite();
	bool teleportCollision(Mesh3Dg *mesh, MapDataType posOffset, uint32_t &pastTime);
	uint32_t teleportDissolve(float x, float z);
	bool equipmentCollision(Mesh3Dg *mesh, uint32_t posOffset);
	uint32_t getDataOffset(MapDataType objOffset, MapDataPtr data);
	uint32_t getFaceDir();
	void doActions(uint32_t dataOffset, MapDataPtr data);
	void searchForEdges(bool *edges, uint8_t posX, uint8_t posZ);
	uint16_t getRelativePosOffset(int8_t posX, int8_t posZ, int8_t relX, int8_t relZ);
	void displayNoise();
	void displayExplosion(Vector3Dg &position, ExplosionType type, uint32_t delay, bool yshift);
	void displayHugeExplosion(Vector3Dg &position, Vector3Dg &direction);
	int32_t calculateVolume(Vector3Dg position, VolumeCalculationMethod method);
	bool isDoorOpen(GODoor *door);
	void damegeWeapon(Weapon *weapon);
	void leaveAmmo(Enemy *enemy);
	void spreadBlood(Enemy *enemy, Vector3Dg direction, float shooterDistaince);
	bool randomTrue(float probability);
	void unregisterFireSounds();
	void randomRoar(Enemy *enemy);
	void hitRoar(Enemy *enemy);
	void actualizeMap(int8_t x, int8_t z, uint16_t walls);
	void checkEnemyCollisions(Enemy *enemy);
	bool canShoot(float range, Vector3Dg position, Vector3Dg direction);
public:
	bool    mImmortal;
	bool    mVisionNoise;
	bool    mHighDificulty;
	float   mExhaust;
	int32_t mCollisionSounds[CSND_NUM_SOUNDS];
	int32_t mDoorSounds[DOORTYPE_NUM_OF_TYPES];
	int32_t mEnemySounds[ESND_NUM_SOUNDS];
	int32_t mWeaponSounds[WSND_NUM_SOUNDS];
	WeaponsMap mEnemyWeapons;

	bool init(UpdateData *data, GameObjectsManager *objects, COGLClass *ogl, CInfoText *texts);
	void release();
	bool update(UpdateData *data);
	void animate();
	void teleportCamera(float x, float z);
	void useItem(UsableItem *item);
	void revealMap();
	void redrawMap();
	void closePrevDoor(uint16_t prevOffset, uint16_t currentPosOffset);
	uint16_t getNumberOfKilledEnemies();
};

GameControl *createGameCtrlInterface();

#endif //_GAMECTRL_H_
