/*  TA3D, a remake of Total Annihilation
    Copyright (C) 2005  Roland BROCHARD

    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 St, Fifth Floor, Boston, MA  02110-1301  USA*/

/*-----------------------------------------------------------------------------------\
|                                         fbi.h                                      |
|  Ce fichier contient les structures, classes et fonctions nécessaires à la lecture |
| des fichiers fbi du jeu totalannihilation qui sont les fichiers de données sur les |
| unités du jeu. Cela inclus les classes pour gérer les différents types d'unités et |
| le système de gestion de liens entre unités.                                       |
|                                                                                    |
\-----------------------------------------------------------------------------------*/

#ifndef __CLASSE_UNIT
#define __CLASSE_UNIT

#ifndef __CLASSE_COB
#include "cob.h"				// Pour la gestion des scripts
#endif

#include "weapons.h"			// Pour la gestion des armes des unités

#define LEVEL0				0x0
#define LEVEL1				0x1
#define LEVEL2				0x2
#define LEVEL3				0x3
#define LEVEL4				0x4
#define LEVEL5				0x5
#define LEVEL6				0x6
#define LEVEL7				0x7
#define LEVEL8				0x8
#define LEVEL9				0x9
#define LEVEL10				0xA
#define COMMANDER_BLAST		0xB
#define ARM					0x10
#define COMMANDER			0x20
#define _WEAPON				0x40
#define NOTAIR				0x80
#define NOTSUB				0x100
#define CTRL_C				0x200
#define BIG_UNITEX			0xC
#define SMALL_BUILDINGEX	0xD
#define LARGE_BUILDINGEX	0xE
#define SMALL_UNITEX		0xF
#define ESTOR_BUILDINGEX	0x10
#define LIGHTNING			0x11
#define ATOMIC_BLASTSML		0x12
#define CRAWL_BLASTSML		0x13
#define CRAWL_BLAST			0x14
#define NUCLEAR_MISSILE		0x15
#define ATOMIC_BLAST		0x16
#define MEDIUM_BUILDINGEX	0x17
#define CORPYRO_BLAST		0x18
#define BIG_UNIT			BIG_UNITEX
#define SMALL_BUILDING		SMALL_BUILDINGEX
#define LARGE_BUILDING		LARGE_BUILDINGEX
#define SMALL_UNIT			SMALL_UNITEX
#define ESTOR_BUILDING		ESTOR_BUILDINGEX
#define MEDIUM_BUILDING		MEDIUM_BUILDINGEX

#define CLASS_UNDEF			0x0000
#define CLASS_WATER			0x0001
#define CLASS_SHIP			0x0002
#define CLASS_ENERGY		0x0003
#define CLASS_VTOL			0x0004
#define CLASS_KBOT			0x0005
#define CLASS_PLANT			0x0006
#define CLASS_TANK			0x0040
#define CLASS_SPECIAL		0x0080
#define CLASS_FORT			0x0100
#define CLASS_METAL			0x0200
#define CLASS_COMMANDER		0x0400
#define CLASS_CNSTR			0x0800

#define MISSION_STANDBY			0x0		// Aucune mission
#define MISSION_VTOL_STANDBY	0x1
#define MISSION_GUARD_NOMOVE	0x2		// Patrouille immobile
#define MISSION_MOVE			0x3		// Déplacement de l'unité
#define MISSION_BUILD			0x4		// Création d'une unité
#define MISSION_BUILD_2			0x5		// Construction d'une unité
#define MISSION_STOP			0x6		// Arrêt des opérations en cours
#define MISSION_REPAIR			0x7		// Réparation d'une unité
#define MISSION_ATTACK			0x8		// Attaque une unité
#define MISSION_AIM				0x9		// Vise une unité
#define MISSION_SHOOT			0xA		// Tire sur une unité

#define MOVEMENT_KBOTSS2	0x0
#define MOVEMENT_BOATD3		0x1
#define MOVEMENT_TANKSH3	0x2
#define MOVEMENT_BOATD6		0x3
#define MOVEMENT_BOATS6		0x4
#define MOVEMENT_TANKSH2	0x5
#define MOVEMENT_SPID3		0x6
#define MOVEMENT_BOATS4		0x7
#define MOVEMENT_TANKDS2	0x8
#define MOVEMENT_KBOTSF2	0x9
#define MOVEMENT_BOATS5		0xA
#define MOVEMENT_TANKBH3	0xB
#define MOVEMENT_TANKDH3	0xC

class UNIT_TYPE			// Structure pour la description des unités du jeu
{
public:
	SCRIPT	*script;			// Scripts de l'unité
	GLuint	glpic;				// Image de l'unité sous forme de texture OpenGl
	MODEL	*model;				// Modèle associé à l'unité
	BITMAP	*unitpic;			// Image de l'unité
	int		SortBias;
	int		AltFromSeaLevel;
	bool	Builder;
	bool	ThreeD;
	char	*Unitname;
	int		FootprintX;
	int		FootprintZ;
	int		Category;
	int		MaxSlope;
	int		BMcode;
	bool	ShootMe;
	bool	norestrict;
	int		StandingMoveOrder;
	int		MobileStandOrders;
	int		StandingFireOrder;
	int		FireStandOrders;
	int		WaterLine;
	int		TEDclass;
	int		BuildAngle;
	int		CruiseAlt;
	int		ManeuverLeashLength;
	int		DefaultMissionType;
	int		TransportSize;
	bool	IsAirBase;
	bool	hoverattack;
	char	*name;				// Nom de l'unité
	byte	version;			// Version
	char	*side;				// Camp de l'unité
	char	*ObjectName;		// Nom interne de l'unité
	char	*Designation_Name;	// Nom visible de l'unité
	char	*Description;		// Description
	int		BuildCostEnergy;	// Energie nécessaire pour la construire
	int		BuildCostMetal;		// Metal nécessaire pour la construire
	int		MaxDamage;			// Points de dégats maximum que l'unité peut encaisser
	int		EnergyUse;			// Energie nécessaire pour faire quelque chose
	int		BuildTime;			// Temps de construction
	int		WorkerTime;			// Vitesse de construction
	bool	AutoFire;			// Tire automatique
	int		SightDistance;		// Distance maximale de vue de l'unité
	int		RadarDistance;		// Distance maximale de detection radar
	int		EnergyStorage;		// Quantité d'énergie stockable par l'unité
	int		MetalStorage;		// Quantité de metal stockable par l'unité
	short	ExplodeAs;			// Type d'explosion lorsque l'unité est détruite
	short	SelfDestructAs;		// Type d'explosion lors de l'autodestruction
	MODEL	*Corpse;			// Restes de l'unité
	int		UnitNumber;			// ID de l'unité
	char	*FrenchName;		// Nom français de l'unité
	char	*FrenchDescription;	// Description française de l'unité
	bool	canmove;			// Indique si l'unité peut bouger
	bool	canpatrol;			// si elle peut patrouiller
	bool	canstop;			// si elle peut s'arrêter
	bool	canguard;			// si elle peut garder une autre unité
	float	MaxVelocity;		// Vitesse maximale
	float	BrakeRate;			// Vitesse de freinage
	float	Acceleration;		// Accélération
	float	TurnRate;			// Vitesse de tournage
	byte	SteeringMode;
	bool	canfly;				// si l'unité peut voler
	float	Scale;				// Echelle
	int		BankScale;
	float	BuildDistance;		// Distance maximale de construction
	bool	CanReclamate;		// si elle peut récupérer
	int		EnergyMake;			// Production d'énergie de l'unité
	float	MetalMake;			// Production de métal de l'unité
	byte	MovementClass;		// Type de mouvement
	bool	Upright;			// Si l'unité est debout
	int		Weapon1;			// Arme 1
	int		wpri_badTargetCategory;	// Type d'unité non ciblable par l'arme 1
	int		BadTargetCategory;		// Type d'unité non attacable
	bool	DamageModifier;
	bool	canattack;			// Si l'unité peut attaquer
	bool	ActivateWhenBuilt;	// L'unité s'active lorsqu'elle est achevée
	bool	onoffable;			// (Dés)activable
	int		MaxWaterDepth;		// Profondeur maximale où l'unité peut aller
	int		MinWaterDepth;		// Profondeur minimale où l'unité peut aller
	bool	NoShadow;			// Si l'unité n'a pas d'ombre
	int		TransMaxUnits;		// Maximum d'unités portables
	bool	canload;			// Si elle peut charger d'autres unités
	int		Weapon2;			// Arme 2
	int		wsec_badTargetCategory;	// Unités non ciblable par l'arme 2
	bool	Floater;			// Si l'unité flotte
	int		NoChaseCategory;	// Type d'unité non chassable
	int		Weapon3;			// Arme 3
	int		SonarDistance;		// Portée du sonar
	bool	candgun;			// si l'unité peut utiliser l'arme ravage
	int		CloakCost;			// Coût en energie pour rendre l'unité invisible
	int		CloakCostMoving;	// Idem mais quand l'unité bouge
	int		HealTime;			// Temps nécessaire à la réparation de l'unité
	bool	CanCapture;			// Si elle peut capturer d'autres unités
	bool	HideDamage;			// Cache la vie de l'unité aux autres joueurs
	bool	ImmuneToParalyzer;	// Immunisation
	bool	Stealth;
	float	MakesMetal;			// Si l'unité produit du métal
	float	ExtractsMetal;		// métal extrait par l'unité
	bool	TidalGenerator;		// Si l'unité est une centrale marée-motrice
	int		TransportMaxUnits;	// Maximum d'unités transportables
	bool	kamikaze;			// Unité kamikaze
	bool	WindGenerator;		// Centrale de type Eolienne
	char	*yardmap;			// Pour indiquer les cases occupées par l'unité
	WEAPON_DEF	*weapon[3];		// Armes

/*-----------------------------------------------------------------------*/

	char	*select1;
	char	*ok1;
	char	*cant1;
	char	*underattack;
	char	*count[6];
	char	*canceldestruct;
	char	*unitcomplete;
	char	*arrived1;
	char	*build;
	char	*repair;
	char	*working;
	char	*cloak;
	char	*uncloak;
	char	*capture;
	char	*activate;
	char	*deactivate;

/*-----------------------------------------------------------------------*/

	int		nb_unit;			// Nombre d'unités que cette unité peut construire
	int		*BuildList;			// Liste des unités que cette unité peut construire

/*-----------------------------------------------------------------------*/

	int		page;				// Pour le menu de construction

/*-----------------------------------------------------------------------*/

	inline void AddUnitBuild(int index)
	{
		if(index<0) return;		// N'ajoute pas d'indices incorrects

		int i;
		if(BuildList && nb_unit>0)		// Vérifie si l'unité n'est pas déjà répertoriée
			for(i=0;i<nb_unit;i++)
				if(BuildList[i]==index)
					return;

		nb_unit++;
		if(BuildList==NULL)
			nb_unit=1;
		int *Blist=(int*) malloc(sizeof(int)*nb_unit);
		if(BuildList && nb_unit>1)
			for(i=0;i<nb_unit-1;i++)
				Blist[i]=BuildList[i];
		Blist[nb_unit-1]=index;
		if(BuildList)
			free(BuildList);
		BuildList=Blist;
	}

	inline void init()
	{
		select1=NULL;
		ok1=NULL;
		cant1=NULL;
		underattack=NULL;
		count[0]=NULL;
		count[1]=NULL;
		count[2]=NULL;
		count[3]=NULL;
		count[4]=NULL;
		count[5]=NULL;
		canceldestruct=NULL;
		unitcomplete=NULL;
		arrived1=NULL;
		build=NULL;
		repair=NULL;
		working=NULL;
		cloak=NULL;
		uncloak=NULL;
		capture=NULL;
		activate=NULL;
		deactivate=NULL;

		weapon[0]=weapon[1]=weapon[2]=NULL;		// Pas d'armes

		script=NULL;		// Aucun script

		page=0;

		nb_unit=0;
		BuildList=NULL;

		yardmap=NULL;
		model=NULL;
		unitpic=NULL;
		hoverattack=false;
		SortBias=0;
		IsAirBase=false;
		AltFromSeaLevel=0;
		TransportSize=0;
		ManeuverLeashLength=640;
		CruiseAlt=0;
		TEDclass=CLASS_UNDEF;
		WaterLine=0;
		StandingMoveOrder=1;
		MobileStandOrders=1;
		StandingFireOrder=1;
		FireStandOrders=1;
		ShootMe=false;
		ThreeD=true;
		Builder=false;
		Unitname=NULL;
		name=NULL;
		version=0;
		side=NULL;
		ObjectName=NULL;
		FootprintX=0;
		FootprintZ=0;
		Category=0;
		MaxSlope=20;
		BMcode=0;
		norestrict=false;
		BuildAngle=10;
		Designation_Name=NULL;	// Nom visible de l'unité
		Description=NULL;		// Description
		BuildCostEnergy=0;		// Energie nécessaire pour la construire
		BuildCostMetal=0;		// Metal nécessaire pour la construire
		MaxDamage=10;			// Points de dégats maximum que l'unité peut encaisser
		EnergyUse=0;			// Energie nécessaire pour faire quelque chose
		BuildTime=0;			// Temps de construction
		WorkerTime=1;			// Vitesse de construction
		AutoFire=false;			// Tire automatique
		SightDistance=50;		// Distance maximale de vue de l'unité
		RadarDistance=50;		// Distance maximale de detection radar
		EnergyStorage=0;		// Quantité d'énergie stockable par l'unité
		MetalStorage=0;			// Quantité de metal stockable par l'unité
		ExplodeAs=0;			// Type d'explosion lorsque l'unité est détruite
		SelfDestructAs=0;		// Type d'explosion lors de l'autodestruction
		Corpse=NULL;			// Restes de l'unité
		UnitNumber=0;			// ID de l'unité
		FrenchName=NULL;		// Nom français de l'unité
		FrenchDescription=NULL;	// Description française de l'unité
		canmove=false;			// Indique si l'unité peut bouger
		canpatrol=false;		// si elle peut patrouiller
		canstop=false;			// si elle peut s'arrêter
		canguard=false;			// si elle peut garder une autre unité
		MaxVelocity=1;			// Vitesse maximale
		BrakeRate=1;			// Vitesse de freinage
		Acceleration=1;			// Accélération
		TurnRate=1;				// Vitesse de tournage
		SteeringMode=0;
		canfly=false;			// si l'unité peut voler
		Scale=1.0f;				// Echelle
		BankScale=0;
		BuildDistance=10.0f;	// Distance maximale de construction
		CanReclamate=false;		// si elle peut récupérer
		EnergyMake=0;			// Production d'énergie de l'unité
		MetalMake=0.0f;			// Production de métal de l'unité
		MovementClass=0;		// Type de mouvement
		Upright=false;			// Si l'unité est debout
		Weapon1=-1;				// Arme 1
		wpri_badTargetCategory=0;	// Type d'unité non ciblable par l'arme 1
		BadTargetCategory=0;	// Type d'unité non attacable
		DamageModifier=false;
		canattack=false;			// Si l'unité peut attaquer
		ActivateWhenBuilt=false;// L'unité s'active lorsqu'elle est achevée
		onoffable=false;		// (Dés)activable
		MaxWaterDepth=10;		// Profondeur maximale où l'unité peut aller
		MinWaterDepth=0;		// Profondeur minimale où l'unité peut aller
		NoShadow=false;			// Si l'unité n'a pas d'ombre
		TransMaxUnits=0;		// Maximum d'unités portables
		canload=false;			// Si elle peut charger d'autres unités
		Weapon2=-1;				// Arme 2
		wsec_badTargetCategory=0;	// Unités non ciblable par l'arme 2
		Floater=false;			// Si l'unité flotte
		NoChaseCategory=0;		// Type d'unité non chassable
		Weapon3=-1;				// Arme 3
		SonarDistance=10;		// Portée du sonar
		candgun=false;			// si l'unité peut utiliser l'arme ravage
		CloakCost=100;			// Coût en energie pour rendre l'unité invisible
		CloakCostMoving=110;	// Idem mais quand l'unité bouge
		HealTime=10;			// Temps nécessaire à la réparation de l'unité
		CanCapture=false;		// Si elle peut capturer d'autres unités
		HideDamage=false;		// Cache la vie de l'unité aux autres joueurs
		ImmuneToParalyzer=false;	// Immunisation
		Stealth=false;
		MakesMetal=0;			// production de métal de l'unité
		ExtractsMetal=0.0f;		// métal extrait par l'unité
		TidalGenerator=false;	// Si l'unité est une centrale marée-motrice
		TransportMaxUnits=0;	// Maximum d'unités transportables
		kamikaze=false;			// Unité kamikaze
		WindGenerator=false;	// Centrale de type Eolienne
	}

	UNIT_TYPE()
	{
		init();
	}

	inline void destroy()
	{
		if(select1)	free(select1);
		if(ok1)	free(ok1);
		if(cant1)	free(cant1);
		if(underattack)	free(underattack);
		for(int i=0;i<6;i++)
			if(count[i])	free(count[i]);
		if(canceldestruct)	free(canceldestruct);
		if(unitcomplete)	free(unitcomplete);
		if(arrived1)	free(arrived1);
		if(build)	free(build);
		if(repair)	free(repair);
		if(working)	free(working);
		if(cloak)	free(cloak);
		if(uncloak)	free(uncloak);
		if(capture)	free(capture);
		if(activate)	free(activate);
		if(deactivate)	free(deactivate);
		if(script)
			free(script);

		if(BuildList)
			free(BuildList);

		if(yardmap)	free(yardmap);
		if(model)
			model=NULL;
		if(unitpic) {
			destroy_bitmap(unitpic);
			glDeleteTextures(1,&glpic);
			}
		if(Unitname)		free(Unitname);
		if(name)		free(name);
		if(side)	free(side);
		if(ObjectName)	free(ObjectName);
		if(Designation_Name)	free(Designation_Name);
		if(Description)	free(Description);
		if(FrenchName)	free(FrenchName);
		if(FrenchDescription)	free(FrenchDescription);

		init();
	}

	~UNIT_TYPE()
	{
		destroy();
	}

private:
	inline char *get_line(char *data)
	{
		int pos=0;
		while(data[pos]!=0 && data[pos]!=13 && data[pos]!=10)	pos++;
		char *d=new char[pos+1];
		memcpy(d,data,pos);
		d[pos]=0;
		return d;
	}
public:

	int load(char *data,int size=99999999);
};

class UNIT_MANAGER			// Classe pour charger toutes les données relatives aux unités
{
public:
	int			nb_unit;		// Nombre d'unités
	UNIT_TYPE	*unit_type;		// Données sur l'unité

	inline void init()
	{
		nb_unit=0;
		unit_type=NULL;
	}

	UNIT_MANAGER()
	{
		init();
	}

	inline void destroy()
	{
		if(nb_unit>0 && unit_type!=NULL) {
			for(int i=0;i<nb_unit;i++)
				unit_type[i].destroy();
			free(unit_type);
			}
		init();
	}

	~UNIT_MANAGER()
	{
		destroy();
	}

	inline int load_unit(byte *data,int size=9999999)			// Ajoute une nouvelle unité
	{
		UNIT_TYPE	*n_type=(UNIT_TYPE*) malloc(sizeof(UNIT_TYPE)*(nb_unit+1));
		int i;
		if(unit_type!=NULL) {
			for(i=0;i<nb_unit;i++)
				n_type[i]=unit_type[i];
			free(unit_type);
			}
		unit_type=n_type;
		unit_type[nb_unit].init();
		return unit_type[nb_unit++].load((char*)data,size);
	}

	inline int get_unit_index(char *unit_name)		// Cherche l'indice de l'unité unit_name dans la liste d'unités
	{
		for(int i=0;i<nb_unit;i++)
			if(strcasecmp(unit_type[i].Unitname,unit_name)==0)
				return i;
		for(int i=0;i<nb_unit;i++)
			if(unit_type[i].name && strcasecmp(unit_type[i].name,unit_name)==0)
				return i;
		for(int i=0;i<nb_unit;i++)
			if(unit_type[i].ObjectName && strcasecmp(unit_type[i].ObjectName,unit_name)==0)
				return i;
		for(int i=0;i<nb_unit;i++)
			if(unit_type[i].Description && strcasecmp(unit_type[i].Description,unit_name)==0)
				return i;
		for(int i=0;i<nb_unit;i++)
			if(unit_type[i].Designation_Name && strcasecmp(unit_type[i].Designation_Name,unit_name)==0)
				return i;
		return -1;
	}

private:
	inline char *get_line(char *data)
	{
		int pos=0;
		while(data[pos]!=0 && data[pos]!=13 && data[pos]!=10)	pos++;
		char *d=new char[pos+1];
		memcpy(d,data,pos);
		d[pos]=0;
		return d;
	}
public:

	inline void analyse(char *data,int unit_index,int size=99999999)
	{
		char *pos=data;
		char *ligne=NULL;
		int nb=0;
		pos=strstr(pos,"\n")+1;
		int totalgadgets=100;
		int curgadget=0;
		int sub=0;
		char *limit=data+size;
		do
		{
			nb++;
			if(ligne)
				delete ligne;
			ligne=get_line(pos);
			strlwr(ligne);
			while(pos[0]!=0 && pos[0]!=13 && pos[0]!=10)	pos++;
			while(pos[0]==13 || pos[0]==10)	pos++;

			if(strstr(ligne,"{"))	sub++;
			if(strstr(ligne,"}")) {
				sub--;
				if(sub==0)	curgadget++;
				}

			if(strstr(ligne,"totalgadgets=")) {		// Entête ?
				totalgadgets=atoi(strstr(ligne,"totalgadgets=")+13);
				}
			else if(strstr(ligne,"name=")) {		// Vérifie s'il s'agit d'une unité et l'ajoute à la liste si c'est le cas
				char *nom=strstr(ligne,"name=")+5;
				if(strstr(nom,";"))
					*(strstr(nom,";"))=0;
				strupr(nom);
				int idx=get_unit_index(nom);
				if(idx>=0 && idx<nb_unit && unit_type[idx].unitpic)
					unit_type[unit_index].AddUnitBuild(idx);
				}

		}while(strlen(ligne)>0 && nb<2000 && curgadget<=totalgadgets && pos<limit);
		delete ligne;
	}

	inline void analyse2(char *data,int size=9999999)
	{
		char *pos=data;
		char *ligne=NULL;
		char *limit=data+size;
		int nb=0;
		do {
			char *unitmenu=NULL;
			char *unitname=NULL;

			do
			{
				nb++;
				if(ligne)
					delete ligne;
				ligne=get_line(pos);
				strlwr(ligne);
				while(pos[0]!=0 && pos[0]!=13 && pos[0]!=10)	pos++;
				while(pos[0]==13 || pos[0]==10)	pos++;

				if(strstr(ligne,"unitmenu=")) {		// Obtient le nom de l'unité dont le menu doit être completé
					unitmenu=strstr(ligne,"unitmenu=")+9;
					if(strstr(unitmenu,";"))
						*(strstr(unitmenu,";"))=0;
					strupr(unitmenu);
					unitmenu=strdup(unitmenu);
					}
				if(strstr(ligne,"unitname=")) {		// Obtient le nom de l'unité à ajouter
					unitname=strstr(ligne,"unitname=")+9;
					if(strstr(unitname,";"))
						*(strstr(unitname,";"))=0;
					strupr(unitname);
					unitname=strdup(unitname);
					}

			}while(strstr(ligne,"}")==NULL && nb<2000 && data<limit);
			delete ligne;
			ligne=NULL;
			if(unitmenu==NULL || unitname==NULL) break;
			int unit_index=get_unit_index(unitmenu);
			if(unit_index==-1) continue;		// Au cas où l'unité n'existerait pas
			int idx=get_unit_index(unitname);
			if(idx>=0 && idx<nb_unit && unit_type[idx].unitpic)
				unit_type[unit_index].AddUnitBuild(idx);
			}while(pos[0]=='[' && nb<2000 && data<limit);
	}

	inline void gather_unit_build_data(HPI_FILE *hpi,char *unit_name)
	{
		int unit_index=get_unit_index(strupr(unit_name));
		if(unit_index==-1) return;		// Au cas où l'unité n'existerait pas
		int n=0;
		char *file;
		int size;

		while(file = hpi->find("/guis",n++)) {		// Cherche un fichier pouvant contenir des informations sur l'unité unit_name
			if(file==NULL) break;
			strupr(file);
			if(strstr(file,unit_name)) {			// A trouvé un fichier qui convient
				byte *data=hpi->extract_memory_file(file,&size);		// Lit le fichier

				analyse((char*)data,unit_index,size);

				free(data);
				}
			}
	}

	inline void gather_build_data(HPI_FILE *hpi)
	{
		int n=0;
		char *file;
		int size;

		while(file = hpi->find("/download",n++)) {		// Cherche un fichier pouvant contenir des informations sur l'unité unit_name
			if(file == NULL) break;
			byte *data=hpi->extract_memory_file(file,&size);		// Lit le fichier

			analyse2((char*)data,size);

			free(data);
			}
	}

	inline void load_script_file(HPI_FILE *hpi,char *unit_name)
	{
		int unit_index=get_unit_index(strupr(unit_name));
		if(unit_index==-1) return;		// Au cas où l'unité n'existerait pas
		int n=0;
		char *file;
		char *uprname=strupr(strdup(unit_name));

		while(file = hpi->find("/scripts",n++)) {		// Cherche un fichier pouvant contenir des informations sur l'unité unit_name
			if(file == NULL) break;
			strupr(file);
			if(strstr(file,".COB") && strstr(file,uprname)) {			// Si le fichier est au bon format
				byte *data=hpi->extract_memory_file(file);		// Lit le fichier

				unit_type[unit_index].script=(SCRIPT*) malloc(sizeof(SCRIPT));
				unit_type[unit_index].script->init();
				unit_type[unit_index].script->load_cob(data);
				}
			free(file);
			}
		free(uprname);
	}

	void load_sound_file(HPI_FILE *hpi);

	int all_units_in_hpi(char *filename);

	int unit_build_menu(int index,int omb);				// Affiche et gère le menu des unités

	inline void Identify()			// Identifie les pièces aux quelles les scripts font référence
	{
		for(int i=0;i<nb_unit;i++)
			if(unit_type[i].script && unit_type[i].model)
				unit_type[i].model->Identify(unit_type[i].script->nb_piece,unit_type[i].script->piece_name);
	}
};

extern UNIT_MANAGER unit_manager;

#endif
