--[[#######################################################################
#  File     :  /hook/lua/EW_DefaultUnits.lua
#  Author(s):  Manimal
#  Summary  :  Default definitions of the following units : 
#   1°) PORTAL FACTORY - Scripted by MANIMAL
#   2°) HERO UNIT - Scripted by MANIMAL
#   3°) STRUCTURE UNIT - Modified by MANIMAL
#   4°) VETERAN FACTORY - Scripted by MANIMAL
#   5°) FACTORY & DERIVED CLASSES - Modified by MANIMAL
#   6°) SUB FACTORY - Scripted by ???
#   7°) LABORATORY & DERIVED CLASSES - Scripted by MANIMAL
#  -----------------------------
#  Revis.by :  Manimal
#  Rev.Date :  14 décembre 2009
#  Rev.Date :  15 juillet 2010 -> LABOS version 5 
#  -----------------------------
#  Copyright © 2009 Gas Powered Games, Inc.  All rights reserved.
#######################################################################]]--

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# À FAIRE :
# ~~~~~~~~~
# ¤ OnCreate DEVRAIT SUFFIR À CONTRER LA TRICHE VIA [ALT][F2]
# ¤ AMÉLIORER GESTION DES ÉCHECS ET ERREURS.
# ¤ VÉRIFIER RECONSTRUCTION DES LABOS APRÈS UN ARRÊT : PAUSE, DÉTRUIT INACHEVÉ, ETC.
# ¤ VÉRIFIER SetMaintenanceConsumptionActive ET SetActiveConsumptionActive
#   -- SetMaintenanceConsumptionActive = function( self )
#   -- SetActiveConsumptionActive = function( self )
# ¤ REVOIR LAYER DE SUB RESEARCH LAB UNIT
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--[[
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# À VOIR :
# ~~~~~~~~
# ¤ UTILISER bp.Display.ShowBuildEffectsDuringUpgrade ? --# COPIÉ DE units.lua
# ¤ UTILISER categories.SORTOTHER DANS LE BP UBC ?
# ¤ VÉRIFIER categories.ABILITYBUTTON --# KOOL !
# ¤ LUA.SCD\LUA\UI\GAME\AVATARS.LUA[630]
#   table[3] = EntityCategoryFilterDown(categories.TECH3 * categories[type], unitData)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]--

#===============================================================================
local Game = import('/lua/game.lua')

# VARIABLE ''GLOBALE'' (par Manimal)
local MyModPath = Game.MyModPath
#===============================================================================


--[[
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Asdrubael-Vect A SPÉCIFIÉ pour le PORTAIL et pour le HÉROS :
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ¤ 1 seul Commandeur, SI DETRUIT => FIN de JEU.
# ¤ 1 Portail UNIQUE + REBUILD SI DETRUIT ou RECYCLÉ.
# ¤ 1 Héros UNIQUE + REBUILD SI DETRUIT.
# ¤ SI TRICHE :
#  => DESTRUCTION des PORTAILS en trop.
#  => DESTRUCTION des HÉROS en trop.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]--
--[[
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Asdrubael-Vect A SPÉCIFIÉ pour les NOUVEAUX BÂTIMENTS UNIQUES : 
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ¤ Centre de Recherches en Combat Terrestre.
# ¤ Centre de Recherches en Combat Aérien.
# ¤ Centre de Recherches en Combat Navals.
# ¤ 3 Niveaux de Technologie Chacun.
# ¤ Si 1 de ces bâtiments est détruit :
# => REBUILD POSSIBLE + AMÉLIORATIONS de GRADES DÉSACTIVÉES.
# ¤ SI TRICHE :
#  => DESTRUCTION des CENTRES de RECHERCHES en trop.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]--



################################################################################
#
#  DÉFINITION UTILES AUX UNITÉS DU MOD Experimental Wars version 2
#
################################################################################


local EffectTemplate = import( '/lua/EffectTemplates.lua' )



#===============================================================================
# IMPORT DES MODULES MODIFIÉS POUR LES BESOINS DE Experimental Wars version 2
#===============================================================================

--[[
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# NOTE DE MANIMAL :
# HOOK ICI DES MODULES IMPORTÉS, FAUTE DE MIEUX (Hook de /lua/defaultunits.lua) 
# AFIN DE FORCER StructureUnit ET FactoryUnit À PRENDRE EN COMPTE MES MODIFS
# DE LA CLASSE Unit LIÉES À OnKilled ET OnDestroy (voir /hook/lua/sim/Unit.lua)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]--

local Unit = import( MyModPath .. '/hook/lua/sim/Unit.lua' ).Unit
local DefaultUnits = import( MyModPath .. '/hook/lua/defaultunits.lua' )
local DefaultStructureUnit = DefaultUnits.StructureUnit
local DefaultFactoryUnit = DefaultUnits.FactoryUnit
local DefaultLandFactoryUnit = DefaultUnits.LandFactoryUnit
local DefaultWalkingLandUnit = DefaultUnits.WalkingLandUnit


#===============================================================================
# DÉFINITIONS DES NOUVELLES VARIABLES DES UNITÉS MODIFIÉES
#===============================================================================

nomType = { 'LAND', 'AIR', 'NAVAL', 'ORBITAL' }    --# TABLE POUR TRACEURS
catTypeUnite = { categories.LAND, categories.AIR, categories.NAVAL, categories.ORBITAL  }
catTechUnite = { categories.TECH1, categories.TECH2, categories.TECH3, categories.EXPERIMENTAL }

catCmndr = categories.COMMAND  --# REMARQUE DE MANIMAL : bizarrement ce n'est pas 'COMMANDER' !!! 
catUsine = categories.FACTORY
--catIngen = categories.ENGINEER   --# INUTILISÉ

--catFactionUnite = { categories.AEON, categories.CYBRAN, categories.UEF, categories.SERAPHIM }
--catTout = categories.ALLUNITS    --# INUTILISÉ


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DÉFINITIONS SPÉCIFIQUES AUX UNITÉS UNIQUES
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

catUnique = categories.UNIQUE
catNonCapturable = categories.NONCAPTURABLE
catPortail = categories.QUANTUMHELPH
catHeros = categories.BUILTBYQUANTUMHELPH


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DÉFINITIONS SPÉCIFIQUES AUX LABOS DE RECHERCHE VETERANS
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

catLabo = categories.LABO
catRecherche = categories.RECHERCHE
catVeteran = categories.VETERAN

--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

NiveauVetMax = Game.NiveauVetMax

--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

UneRechercheParDefaut = {
	nomDeRecherche = 'NEANT',
	niveauDeRecherche = 0,
}

--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--[[
--# POUR INFO
ListeSyncEx =  {
	{
		army = false,
		id = false,
		type = false,
		tech = false
	},
}
]]--

--# TOUS LES IDENTIFIANTS DES USINES CONSTRUITES, TRIÉS PAR TYPE ET PAR TECH
ListeSyncUsines = {}

--# TOUS LES IDENTIFIANTS DES INGÉNIEURS CONSTRUITS, TRIÉS PAR TYPE ET PAR TECH
--ListeSyncIngenieurs = {}

--# TOUS LES IDENTIFIANTS DES LABOS CONSTRUITS, TRIÉS PAR TYPE ET PAR TECH
ListeSyncLabos = {}


--[[
--# POUR INFO
LaboReinitEx =  {
	{
		army = false,
		bpid = false
	},
}
]]--

--# TOUS LES IDENTIFIANTS DES LABOS CONSTRUITS, TRIÉS PAR TYPE ET PAR TECH
LaboReInit = {}


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# DÉFINITIONS AUTRES
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--[[# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# REMARQUE DE MANIMAL :
	# CERTAINES UNITÉS POSSÈDENT 1 RADAR INTÉGRÉ ET/OU 1 SHIELD.
	# ON IGNORE DONC LES RADARS ET ASSIMILÉS + LES SHIELDS.
	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--





################################################################################
#
# FONCTIONS UTILES AUX UNITÉS DU MOD Experimental Wars version 2
#
################################################################################


# Déterminer si la variable est un nombre
EstUnNombre = function( variable )
	if  not variable  or  variable == nil  then  return false  end
	return  type( variable ) == 'number'
end

# Déterminer si la variable est un booléen
EstUnBooleen = function( variable )
	if  not variable  or  variable == nil  then  return false  end
	return  type( variable ) == 'boolean'
end


# Déterminer si la Construction est l'Unité Particulière
EstUneEntiteUnique = function( unite )
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	return  EntityCategoryContains( catUnique, unite )
end

# Déterminer si la Construction est NONCAPTURABLE
EstNonCapturable = function( unite )
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	return  EntityCategoryContains( catNonCapturable, unite )
end

# Déterminer si la Construction est HEROS
EstUnHeros = function( unite )
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	return  EntityCategoryContains( catHeros, unite )
end

# Déterminer si la Construction est GATE
EstUnPortail = function( unite )
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	return  EntityCategoryContains( catPortail, unite )
end

# Déterminer si la Construction est LABO
EstUnLabo = function( unite )
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	return  EntityCategoryContains( catLabo, unite )
end

# Déterminer si la Construction est RECHERCHE
EstUneRecherche = function( unite )
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	return  EntityCategoryContains( catRecherche, unite )
end

# Déterminer si la Construction est FACTORY
EstUneUsine = function( unite )
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	return  EntityCategoryContains( catUsine, unite )
end


--# GENÈRE LA CATÉGORIE À PARTIR DE unitId
CategorieIdUnite = function( idUnite )
	if  not idUnite  or  idUnite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	idUnite = string.lower( tostring( idUnite ) )
	local categorieUniteAvecId = ParseEntityCategory( string.format( '%s', idUnite ) )

	return categorieUniteAvecId
end




--#=============================================================================
--# NOTE by MANIMAL : FUNCTIONS DON'T WORK WHEN BEING PART OF CLASS DefaultUnits
--#=============================================================================

--[[
-- DÉTAIL DES FONCTIONS
--IndexFactionUnite      --# Nombre de 1 à 4, INUTILISÉ + GÉNÈRE UN BUG À CAUSE DE GetArmy() !!!
--CategorieFactionUnite  --# Ex: category.AEON  --# INUTILISÉ
--IndexTypeUnite         --# Nombre de 1 à 3, UTILISÉ PAR LABOS + USINES
--CategorieTypeUnite     --# Ex: category.LAND, UTILISÉ PAR LABOS
--IndexTechUnite         --# Nombre de 1 à 4, UTILISÉ PAR LABOS + USINES
--CategorieTechUnite     --# Ex: category.TECH1  --# INUTILISÉ
--CategorieIdUnite       --# Ex: category.uel0001  --# INUTILISÉ
]]--


--[[  --# INUTILISÉ
--# GÉNÈRE UN BUG GetArmy() <=> nil SI CETTE FONCTION EST INTÉGRÉE DANS StructureUnit !!!

IndexFactionUnite = function( unite )  --# INDEX DE LA FACTION DE L'UNITÉ
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	local brain = GetArmyBrain( unite:GetArmy() )
	if brain then
		return brain:GetFactionIndex()  --# INDEX DE LA FACTION DE L'UNITÉ
	end
end
]]--


--[[  --# INUTILISÉ
--# GÉNÈRE UN BUG GetArmy() <=> nil SI CETTE FONCTION EST INTÉGRÉE DANS StructureUnit !!!

CategorieFactionUnite = function( unite )  --# CATEGORIE DE LA FACTION DE L'UNITÉ
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	local iFaction = IndexFactionUnite( unite )
	return catFactionUnite[iFaction]  --# CATEGORIE DE LA FACTION DE L'UNITÉ
end
]]--


IndexTypeUnite = function( unite )  --# INDEX DU TYPE DE L'UNITÉ
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	for iType, categ in ipairs( catTypeUnite ) do
		if  EntityCategoryContains( categ, unite ) then
			return iType  --# INDEX DU TYPE DE L'UNITÉ
		end
	end

	return false
end


CategorieTypeUnite = function( unite )  --# CATEGORIE DU TYPE DE L'UNITÉ
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	local iType = IndexTypeUnite( unite )
	if  iType  then
		return catTypeUnite[iType]  --# CATEGORIE DU TYPE DE L'UNITÉ
	end

	return false
end


IndexTechUnite = function( unite )  --# INDEX DU NIVEAU TECH DE L'UNITÉ
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	for iNiveauTech, categ in ipairs( catTechUnite ) do
		if EntityCategoryContains( categ, unite ) then
			return iNiveauTech  --# INDEX DU NIVEAU TECH DE L'UNITÉ
		end
	end

	return false
end


CategorieTechUnite = function( unite )  --# CATEGORIE DU NIVEAU TECH DE L'UNITÉ
	if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	local iNiveauTech = IndexTechUnite( unite )
	if  iNiveauTech  then
		return catTechUnite[iNiveauTech]  --# CATEGORIE DU NIVEAU TECH DE L'UNITÉ
	end

	return false
end


--#=============================================================================
--# AUTRES FONCTIONS UTILES :
--#=============================================================================

RestreindreConstructionParCategorie = function( constructeur, catUnite )
	if  not constructeur  or  constructeur == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	if  not catUnite  or  catUnite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	constructeur:AddBuildRestriction( catUnite )
	constructeur:RequestRefreshUI()
end


PermettreConstructionParCategorie = function( constructeur, catUnite )
	if  not constructeur  or  constructeur == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
	if  not catUnite  or  catUnite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

	constructeur:RemoveBuildRestriction( catUnite )
	constructeur:RequestRefreshUI()
end


--#=============================================================================
--# FONCTION SPÉCIALE LABO :
--#=============================================================================

--[[ 
]]--



################################################################################
#
#  (LAND) PORTAL FACTORY UNIT - SCRIPT DE MANIMAL
#
################################################################################

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AVERTISSEMENT :
# Le Commandeur, le Portail et le Héros SONT LIÉS.
# NE PAS MODIFIER CE SCRIPT SANS EN AVOIR COMPRIS LE FONCTIONNEMENT,
# CAR RISQUE DE PLANTER LE JEU.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# WARNING:
# DO NOT ALTER THIS SCRIPT UNLESS YOU KNOW WHAT YOU'RE DOING (GAME WOULD CRASH)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


PortalFactoryUnit = Class( DefaultLandFactoryUnit ) {

	idPerePortail = false,  # INDISPENSABLE POUR OnDestroy


    OnCreate = function( self )
        DefaultLandFactoryUnit.OnCreate( self )

		local message = '\n\nMANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit -> OnCreate : '

		if IsUnit( self ) and EstUneEntiteUnique( self ) and EstUnPortail( self ) then
			local idUnite = self:GetUnitId() or "UNITE INCONNUE"
			local idEntite = self.Sync.id or "IDENTIF. INCONNUE"
			local armee = self:GetArmy()
			
			message = message .. '  EstUneEntiteUnique'
			if EstNonCapturable( self ) then
				self:SetCapturable( false )
				message = message .. '  EstNonCapturable'
			end
			message = message .. '  armee = ' .. tostring(armee) .. '  UnitId Portail = ' .. tostring(idUnite) .. '  SyncId Portail = ' .. tostring(self.Sync.id) .. '\n'
		end

		LOG( message )
    end,


    OnReclaimed = function( self, entity )
        DefaultLandFactoryUnit.OnReclaimed( self, entity )

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		local idEntity = entity:GetUnitId() or "UNITE INCONNUE"
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnReclaimed  :  UNITE RECYCLEE ' .. tostring(idUnite) .. '  PAR  ' .. tostring(idEntity) .. '\n'  )
    end,


    OnKilled = function( self, instigator, type, overkillRatio )

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnKilled  :  ' .. idUnite .. '  instigator = ' .. tostring(instigator) .. '  type = ' .. tostring(type)  )

		if self.UnitBeingBuilt and not self.UnitBeingBuilt:IsDead() and self.UnitBeingBuilt:GetFractionComplete() != 1 then
			local uBBid = self.UnitBeingBuilt:GetUnitId()
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnKilled  :  PORTAIL -> UNITE EN CONSTRUCTION ' .. tostring(uBBid) .. ' !!!\n' )
		end

		#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		# REMARQUE DE MANIMAL : 
		# ~~~~~~~~~~~~~~~~~~~~~ 
		# FactoryUnit.OnKilled FAIT Destroy() POUR RIEN APRÈS Kill() DANS Unit.OnKilled !!!
		# ON UTILISERA DONC MON CORRECTIF DE FactoryUnit.OnKilled À LA PLACE DE FactoryUnit.OnKilled ORIGINAL
		#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        DefaultLandFactoryUnit.OnKilled(self, instigator, type, overkillRatio)
    end,


    OnDestroy = function( self )

		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnDestroy  :' )

		if IsUnit( self ) and EstUneEntiteUnique( self ) and EstUnPortail( self ) then

			local idUnite = self:GetUnitId() or "UNITE INCONNUE"
			local idEntite = self.Sync.id or "IDENTIFICATION INCONNUE"
			local armee = self:GetArmy()
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnDestroy  :  armee = ' .. tostring(armee) .. '  UnitId Portail = ' .. tostring(idUnite) ..  '  SyncId Portail = '.. tostring(idEntite) )

			--# NOTIFICATION DU CONSTRUCTEUR ( UBC )
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local zeUBC = false
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnDestroy  :  idPerePortail = ' .. tostring(self.idPerePortail) .. '  (type = ' .. type(self.idPerePortail) .. ')' )

			if  self.idPerePortail != nil  and  self.idPerePortail != false  then
				zeUBC = GetUnitById( self.idPerePortail )
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnDestroy  :  zeUBC -> Sync.id = ' .. tostring(zeUBC.Sync.id) .. '  (type = ' .. type(zeUBC.Sync.id) .. ')   Sync.army = ' .. tostring(zeUBC.Sync.army) .. '  (type = ' .. type(zeUBC.Sync.army) .. ')' )
			end
			if  zeUBC != false  and  zeUBC != nil  and  not zeUBC:IsDead()  then
				--# PERMETTRE LA RECONSTRUCTION DU PORTAIL !
				--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				local catPortailDetruit = CategorieIdUnite( idUnite )

				zeUBC:RemoveBuildRestriction( catPortailDetruit )  -- DÉBLOQUER LE PORTAIL DÉTRUIT UNIQUEMENT
				zeUBC:RequestRefreshUI()
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnDestroy  :  SIGNAL UBC = Portail MORT !'  )
			end

		end
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnDestroy  :  PORTAIL MORT !\n\n'  )

        DefaultLandFactoryUnit.OnDestroy( self )
    end,


    OnStartBeingBuilt = function( self, builder, layer )

		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnStartBeingBuilt  :' )

		if IsUnit( self ) and EstUneEntiteUnique( self ) and EstUnPortail( self ) then

			local idUnite = self:GetUnitId() or "UNITE INCONNUE"
			local idUniteBuilder = builder:GetUnitId() or "UNITE INCONNUE"
			local armee = self:GetArmy()

			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnStartBeingBuilt  :  CONSTRUCTION DE PORTAIL '.. tostring(idUnite) .. '  PAR  ' .. tostring(idUniteBuilder) )

			# NOTIFICATION DU CONSTRUCTEUR ( UBC )
			# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			builder:AddBuildRestriction( catPortail * catUnique )
			builder:RequestRefreshUI()
			self.idPerePortail = builder.Sync.id  --# INDISPENSABLE POUR OnDestroy

			# HEROS ORPHELIN -> ADOPTION !
			# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local zeHEROS = false

			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnStartBeingBuilt  :  builder -> idHeros = ' .. tostring(builder.idHeros) .. '  (type = ' .. type(builder.idHeros) .. ')' )

			if  builder.idHeros != false  and  builder.idHeros != nil  then
				--self.idHeros = builder.idHeros  --# POUR USAGE FUTUR: RÉCUPÉRATION id HÉROS VIA UBC
				zeHEROS = GetUnitById( builder.idHeros )
				LOG( 'MANIMAL TRACEUR  OnStartBeingBuilt :  zeHEROS -> Sync.id = ' .. tostring(zeHEROS.Sync.id) .. '  (type = ' .. type(zeHEROS.Sync.id) .. ')   Sync.army = ' .. tostring(zeHEROS.Sync.army) .. '  (type = ' .. type(zeHEROS.Sync.army) .. ')' )
			end
			if  zeHEROS != false  and  zeHEROS != nil  and  not zeHEROS:IsDead()  then
				# FILTRAGE DES FACTIONS DANS CATEGORIES !
				self:AddBuildRestriction( catUnique * catHeros )	--self:AddBuildRestriction( self.catUnique )
				self:RequestRefreshUI()
				zeHEROS.idPereHeros = self.Sync.id	--# HEROS VIVANT DOIT CONNAITRE SON NOUVEAU PÈRE (pour zeHEROS.OnDestroy -> BuildRestrictions)!!!
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnStartBeingBuilt  :  ADOPTION HEROS Orphelin du Portail !'  )
			end

		end
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnStartBeingBuilt  :  PORTAIL EN COURS de CONSTRUCTION !\n'  )

		DefaultLandFactoryUnit.OnStartBeingBuilt( self, builder, layer )
    end,


    OnFailedToBuild = function( self )
        DefaultLandFactoryUnit.OnFailedToBuild( self )

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  PortalFactoryUnit  ->  OnFailedToBuild  :  ' .. tostring(idUnite)  )
    end,


}




################################################################################
#
#  HERO UNIT - SCRIPT DE MANIMAL
#
################################################################################

#-------------------------------------------------------------
#  HERO WALKING LAND UNIT
#-------------------------------------------------------------

HeroWalkingLandUnit = Class( DefaultWalkingLandUnit ) {

	idPerePortail = false,
	idPereHeros = false,  --# INDISPENSABLE POUR OnDestroy


    OnCreate = function( self )

        DefaultWalkingLandUnit.OnCreate( self )

		local message = '\n\nMANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnCreate : '

		if IsUnit( self ) and EstUneEntiteUnique( self ) and EstUnHeros( self ) then
			local idUnite = self:GetUnitId() or "UNITE INCONNUE"
			local idEntite = self.Sync.id or "IDENTIF. INCONNUE"
			local armee = self:GetArmy()

			message = message .. '  EstUneEntiteUnique '
			if EstNonCapturable( self ) then
				self:SetCapturable( false )
				message = message .. '  EstNonCapturable'
			end
			message = message .. '  armee = ' .. tostring(armee) .. '  UnitId Heros = '.. tostring(idUnite) .. '  SyncId Heros = '.. tostring(self.Sync.id) .. '\n'
		end
		LOG( message )
    end,


    OnReclaimed = function( self, entity )

        DefaultWalkingLandUnit.OnReclaimed( self, entity )

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		local idEntity = entity:GetUnitId() or "UNITE INCONNUE"
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnReclaimed  :  UNITE RECYCLEE ' .. tostring(idUnite) .. '  PAR  ' .. tostring(idEntity) .. '\n'  )
    end,


    OnKilled = function( self, instigator, type, overkillRatio )

        DefaultWalkingLandUnit.OnKilled( self, instigator, type, overkillRatio )

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnKilled  :  ' .. tostring(idUnite) .. '  instigator = ' .. tostring(instigator) .. '  type = ' .. tostring(type) .. '\n' )
    end,


    OnDestroy = function( self )

		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy : ' )

		if IsUnit( self ) and EstUneEntiteUnique( self ) and EstUnHeros( self ) then

			local idUnite = self:GetUnitId() or "UNITE INCONNUE"
			local idEntite = self.Sync.id or "IDENTIF. INCONNUE"
			local armee = self:GetArmy()
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy :  armee = ' .. tostring(armee) .. '  UnitId Heros = ' .. tostring(idUnite) ..  '  SyncId Heros = '.. tostring(idEntite)  )

			# NOTIFICATION DU CONSTRUCTEUR DU HEROS (PORTAIL)
			# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy  :  idPereHeros = ' .. tostring(self.idPereHeros) .. '  (type = ' .. type(self.idPereHeros) .. ')' )
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy  :  idPerePortail = ' .. tostring(self.idPerePortail) .. '  (type = ' .. type(self.idPerePortail) .. ')' )

			local zePORTAIL = false
			if  self.idPereHeros != false  and  self.idPereHeros != nil  then
				zePORTAIL = GetUnitById( self.idPereHeros )
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy  :  zePORTAIL -> Sync.id = ' .. tostring(zePORTAIL.Sync.id) .. '  (type = ' .. type(zePORTAIL.Sync.id) .. ')   Sync.army = ' .. tostring(zePORTAIL.Sync.army) .. '  (type = ' .. type(zePORTAIL.Sync.army) .. ')' )
			end

			if  zePORTAIL != false  and  zePORTAIL != nil  and  not zePORTAIL:IsDead()  then
				# PERMETTRE LA RECONSTRUCTION DU HÉROS !
				# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				local catHerosDetruit = CategorieIdUnite( idUnite )

				zePORTAIL:RemoveBuildRestriction( catHerosDetruit )  -- DÉBLOQUER LE HÉROS DÉTRUIT UNIQUEMENT
				zePORTAIL:RequestRefreshUI()

				zePORTAIL.idHeros = false   --# HEROS MORT PORTAIL PEUT CRÉER 1 HEROS

				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy  :  SIGNAL Portail = Heros EST MORT !\n'  )
			end

			# NOTIFICATION DU CONSTRUCTEUR DU PORTAIL (UBC)
			# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local zeUBC = false
			if  self.idPerePortail != false  and  self.idPerePortail != nil  then
				zeUBC = GetUnitById( self.idPerePortail )
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy  :  zeUBC -> Sync.id = ' .. tostring(zeUBC.Sync.id) .. '  (type = ' .. type(zeUBC.Sync.id) .. ')   Sync.army = ' .. tostring(zeUBC.Sync.army) .. '  (type = ' .. type(zeUBC.Sync.army) .. ')' )
			end

			if  zeUBC != false  and  zeUBC != nil  and  not zeUBC:IsDead()  then
				zeUBC.idHeros = false --# INFORMER UBC : HEROS MORT

				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy  :  SIGNAL UBC = Heros EST MORT !'  )
			end

		end

		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnDestroy  :  SIGNAL HEROS DISPO !\n\n'  )

        DefaultWalkingLandUnit.OnDestroy( self )
    end,


    OnStartBeingBuilt = function(self, builder, layer)

		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnStartBeingBuilt  :  ' )

		if IsUnit( self ) and EstUneEntiteUnique( self ) and EstUnHeros( self ) then

			local idUnite = self:GetUnitId() or "UNITE INCONNUE"
			local idUniteBuilder = builder:GetUnitId() or "UNITE INCONNUE"
			local armee = self:GetArmy()

			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnStartBeingBuilt  :  CONSTRUCTION DE HEROS '.. tostring(idUnite) .. '  PAR  ' .. tostring(idUniteBuilder) )

			# NOTIFICATION DU CONSTRUCTEUR DU HEROS (PORTAIL)
			# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			builder:AddBuildRestriction( catUnique * catHeros )
			builder:RequestRefreshUI()

			self.idPereHeros = builder.Sync.id  --# INDISPENSABLE POUR OnDestroy !

			# NOTIFICATION DU CONSTRUCTEUR DU PORTAIL (UBC)
			# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local zeUBC = false
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnStartBeingBuilt  :  builder -> idPerePortail = ' .. tostring(builder.idPerePortail) .. '  (type = ' .. type(builder.idPerePortail) .. ')' )

			if  builder.idPerePortail != false  and  builder.idPerePortail != nil  then
				self.idPerePortail = builder.idPerePortail  --# RÉCUPÉRATION id UBC
				zeUBC = GetUnitById( builder.idPerePortail )
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnStartBeingBuilt  :  zeUBC -> Sync.id = ' .. tostring(zeUBC.Sync.id) .. '  (type = ' .. type(zeUBC.Sync.id) .. ')   Sync.army = ' .. tostring(zeUBC.Sync.army) .. '  (type = ' .. type(zeUBC.Sync.army) .. ')' )
			end
			if  zeUBC != false  and  zeUBC != nil  and  not zeUBC:IsDead()  then
				zeUBC.idHeros = self.Sync.id  --# SIGNALER NOUVEAU HEROS !
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnStartBeingBuilt  :  SIGNAL UBC = NOUVEAU Heros !'  )
			end

		end
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnStartBeingBuilt  :  SIGNAL HEROS INDISPONIBLE !\n'  )

        DefaultWalkingLandUnit.OnStartBeingBuilt( self, builder, layer )
    end,


    OnFailedToBuild = function( self )

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  HeroWalkingLandUnit  ->  OnFailedToBuild  :  ' .. tostring(idUnite)  )

        DefaultWalkingLandUnit.OnFailedToBuild( self )
    end,


}




################################################################################
#
#  STRUCTURE UNIT - SCRIPT DE MANIMAL
#
################################################################################


--# REDÉFINITION INDISPENSABLE POUR PRISE EN COMPTE DE MES BUG FIXES

StructureUnit = Class( DefaultStructureUnit ) {

--[[
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# BUG FIX BY MANIMAL :
	# I NOTICED THAT MANY CLASSES DO NOT DEFIME OnStopBuild THE SAME WAY FOR MOST OF THE FACTORIES
	# WHEN OnStopBuild IS FIRED FROM AIR AND/OR NAVAL FACTORY UNITS, THE VALUE OF order IS nil !!!
	# THE PROBLEM LIES WITHIN xxxxunits.lua (xxxx = faction name) THAT DEFINES UNCONSISTENTLY OnStopBuild
	# FOR AIR + SEA + SUB FactoryUnit CLASSES, THAT DOES NOT MATCH AT ALL THE DEFINITION OF GENERIC FactoryUnit WITHIN defaultunits.lua !!!
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# J'AI REMARQUÉ QUE PLUSIEURS CLASSES DÉFINISSENT OnStopBuild DIFFÉREMMENT POUR LA PLUPART DES USINES
	# PENDANT LA CONSTRUCTION D'UNITÉS AIR ET/OU NAVAL, LA VALEUR DE order EST nil !!!
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

    OnStopBuild = function( self, unitBeingBuilt, order )
        DefaultStructureUnit.OnStopBuild( self, unitBeingBuilt, order  )
    end,  --# END OnStopBuild


--[[
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# BUG FIX BY MANIMAL :  SEE hook/lua/sim/unit.lua
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

    OnKilled = function( self, instigator, type, overkillRatio )
        DefaultStructureUnit.OnKilled( self, instigator, type, overkillRatio )

		if self.UnitBeingBuilt and not self.UnitBeingBuilt:IsDead() and self.UnitBeingBuilt:GetFractionComplete() != 1 then
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			--# MUDIF PAR MANIMAL : VOIR hook/lua/sim/unit.lua
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            --self.UnitBeingBuilt:Destroy()  # USELESS SINCE DIRECTLY MANAGED BY Unit.OnKilled ! ( INHERITANCE FROM StructureUnit. DOUBLE CHEKCED BY MANIMAL )
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        end
    end,


}




################################################################################
#
#  VETERAN FACTORY UNIT - SCRIPT DE MANIMAL
#
################################################################################


VeteranFactoryUnit = Class( StructureUnit ) {

	--# ~~~~~~~~~~~~~~~~~~~~
	--# INIT
	--# ~~~~

	idPereDeUsine = false,    --# UBC OU INGÉ "PÈRE" DE L'USINE (voir OnStartBuild)
	NiveauxVeteran = {},      --# 0, 0, 0, 0 # TOUS NIV TECH

	--# ~~~~~~~~~~~~~~~~~~~~

	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# NOTE DE MANIMAL : GESTION DE LISTE SYNC USINES  ( POUR LABO )
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--[[ 
		ListeSyncExemple =  {
			{
				army = number,
				id = string,
				type = number,
				tech = number
			},
		}
	]]--

	IndexIdUniteDansListeSyncUsines = function( self )

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return false  end  --# POUR GESTION ERREUR

		--# LISTE VIDE => CAS OÙ LISTE (RÉ)INITIALISÉES ( VOIR EN HAUT DE PAGE )
		if  table.getsize( ListeSyncUsines ) <= 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  IndexIdUniteDansListeSyncUsines  :  LISTE SYNC VIDE POUR ARMEE ' .. tostring(self.Sync.army) .. '  !!!  ListeSyncUsines = ' .. repr(ListeSyncUsines) .. ' ' )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false  --# LISTE SYNC VIDE !!!
		end

		for index, uneSync in ipairs( ListeSyncUsines ) do
			if   uneSync.id     and  uneSync.id != nil     and  uneSync.id == self.Sync.id
			and  uneSync.army   and  uneSync.army != nil   and  uneSync.army == self.Sync.army
			and  uneSync.type   and  uneSync.type != nil   and  uneSync.type == typeBatiment
			and  uneSync.tech   and  uneSync.tech != nil   and  uneSync.tech == niveauTech  then
				return index  --# POUR ACCÈS RAPIDE À ID UNITÉ DANS ListeSyncUsines
			end
		end

		return 0  --# SIGNALER ZÉRO ÉLÉMENTS TROUVÉS
	end,


	AjouterIdUniteDansListeSyncUsines = function( self )

		local idArmee = self.Sync.army  --# POUR TRAITER UNITÉ PAR ARMÉE

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return false  end  --# POUR GESTION ERREUR

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  AjouterIdUniteDansListeSyncUsines  :  UNITE ' .. tostring(self:GetUnitId()) .. '  ID ' .. tostring(self.Sync.id) .. ' ARMEE ' .. tostring(self.Sync.army) .. '  ' .. nomType[typeBatiment] .. '  TECH' .. tostring(niveauTech) )
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  AjouterIdUniteDansListeSyncUsines  :  LISTE SYNC  AVANT = ' .. repr(ListeSyncUsines) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		local indexUnite = self.IndexIdUniteDansListeSyncUsines( self )

		--# PROBLÈME => VÉRIFIER LE SCRIPT OU LA FONCTION IndexIdUniteDansListeSyncUsines !!!
		if  indexUnite == nil  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  AjouterIdUniteDansListeSyncUsines  :  PROBLÈME => VÉRIFIER LE SCRIPT OU LA FONCTION IndexIdUniteDansListeSyncUsines !!!  indexUnite = ' .. tostring(indexUnite) .. '  (type = ' .. type(indexUnite) .. ')  #  ListeSyncUsines = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		##### CONTROLE DU SCRIPT EN COURS DE DEVELOPPEMENT #####  SUPPRIMER ENSUITE
		--# LISTE SYNC VIDE  => AUCUN PROBLEME !!!
		if  EstUnBooleen( indexUnite )  and  indexUnite == false  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  AjouterIdUniteDansListeSyncUsines  :  LISTE SYNC VIDE (false) => AUCUN PROBLEME !!!  indexUnite = ' .. tostring(indexUnite) .. '  (type = ' .. type(indexUnite) .. ')  #  ListeSyncUsines = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		end

		##### CONTROLE DU SCRIPT EN COURS DE DEVELOPPEMENT #####  SUPPRIMER ENSUITE
		--# ID NON RÉPERTORIÉ  => AUCUN PROBLEME !!!
		if  EstUnNombre( indexUnite )  and  indexUnite == 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  AjouterIdUniteDansListeSyncUsines  :  ID UNITE NON REPERTORIE => AUCUN PROBLEME !!!  indexUnite = ' .. tostring(indexUnite) .. '  (type = ' .. type(indexUnite) .. ')  #  ListeSyncUsines = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		end

		--# ID UNITÉ DÉJÀ RÉPERTORIÉ ! ( => ÉCRASER CET ÉLÉMENT ? )
		if  EstUnNombre( indexUnite )  and  indexUnite > 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  AjouterIdUniteDansListeSyncUsines  :  ID UNITE DEJA REPERTORIE !!!  indexUnite = ' .. tostring(indexUnite) .. '  (type = ' .. type(indexUnite) .. ')  #  ListeSyncUsines = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		local nouvelleUsine = {
				army = self.Sync.army,
				id = self.Sync.id,
				bpid = self:GetUnitId(),
				type = typeBatiment,
				tech = niveauTech
		}

		--# INSÉRER DANS LISTE DES ID USINES
		table.insert( ListeSyncUsines, nouvelleUsine ) --# TRANSFERT ID LAB0

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  AjouterIdUniteDansListeSyncUsines  :  ListeSyncUsines  APRES = ' .. repr(ListeSyncUsines) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		return true  --# POUR GESTION ERREUR
	end,


	RetirerIdUniteDansListeSyncUsines = function( self )

		local idArmee = self.Sync.army  --# POUR TRAITER UNITÉ PAR ARMÉE

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return false  end  --# POUR GESTION ERREUR

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  RetirerIdUniteDansListeSyncUsines  :  UNITE ' .. tostring(self:GetUnitId()) .. '  id ' .. tostring(self.Sync.id) .. ' ARMEE ' .. tostring(self.Sync.army) .. '  [' .. nomType[typeBatiment] .. '][TECH' .. tostring(niveauTech) ..  ']' )
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  RetirerIdUniteDansListeSyncUsines  :  ListeSyncUsines  AVANT = ' .. repr(ListeSyncUsines) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		local indexUnite = self.IndexIdUniteDansListeSyncUsines( self )

		--# PROBLÈME => VÉRIFIER LE SCRIPT OU LA FONCTION IndexIdUniteDansListeSyncUsines !!!
		if  indexUnite == nil  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  RetirerIdUniteDansListeSyncUsines  :  PROBLÈME => VÉRIFIER LE SCRIPT OU LA FONCTION IndexIdUniteDansListeSyncUsines !!!  indexUnite = ' .. tostring(indexUnite) .. '  #  ListeSyncUsines = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		--# LISTE SYNC VIDE => RIEN À RETIRER DE LA LISTE !!!
		if  EstUnBooleen( indexUnite )  and  indexUnite == false  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  RetirerIdUniteDansListeSyncUsines  :  LISTE SYNC VIDE => RIEN À RETIRER DE LA LISTE !!!  indexUnite = ' .. tostring(indexUnite) .. '  #  ListeSyncUsines = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		--# ID UNITE INEXISTANT => RIEN À RETIRER DE LA LISTE !!!
		if  EstUnNombre( indexUnite )  and  indexUnite == 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  RetirerIdUniteDansListeSyncUsines  :  ID UNITE INEXISTANT => RIEN À RETIRER DE LA LISTE !!!  indexUnite = ' .. tostring(indexUnite) .. '  #  ListeSyncUsines = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		--# ID NON RÉPERTORIÉ => RETIRER ID UNITÉ DE LA LISTE !
		if  EstUnNombre( indexUnite )  and  indexUnite > 0  then
			table.remove( ListeSyncUsines, indexUnite )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  RetirerIdUniteDansListeSyncUsines  : ID UNITE NON REPERTORIE  ->  ListeSyncUsines  APRES  = ' .. repr(ListeSyncUsines) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		end

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  RetirerIdUniteDansListeSyncUsines  :  VERIF  ListeSyncUsines  APRES  = ' .. repr(ListeSyncUsines) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		return true  --# POUR GESTION ERREUR
	end,


	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--[[
]]--

	RecupInfosDeLaRechercheDansLabo = function( self, unite )
		if  unite == nil  or  unite == false  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

		local infosDeRecherche = false
		--# DÉTERMINER SI DEMANDEUR EST LABO / RECHERCHE  (OU BIEN USINE, ETC)
		if  EntityCategoryContains( catLabo, unite ) then
			infosDeRecherche = unite.InfosDeLaRecherche( unite )
		end

		return infosDeRecherche
	end,


	RecupNomDeRechercheDansLabo = function( self, unite )
		if  unite == nil  or  unite == false  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

		local nomDeRecherche = false
		if  EntityCategoryContains( catLabo, unite ) then
			nomDeRecherche = unite.NomDeLaRecherche( unite )
		end

		return nomDeRecherche
	end,


	RecupNiveauDeRechercheDansLabo = function( self, unite )
		if  unite == nil  or  unite == false  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

		local niveauDeRecherche = false
		if  EntityCategoryContains( catLabo, unite ) then
			niveauDeRecherche = unite.NiveauDeLaRecherche( unite )
		end

		return niveauDeRecherche
	end,


	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--[[
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--# NOTE DE MANIMAL :
--# ~~~~~~~~~~~~~~~~~
--# RÉCUPÈRER INFOS DE RECHERCHE EFFECTUÉE POUR MISE à JOUR NIVEAUX VÉTÉRANS.
--# SERA APPELÉ À LA CRÉATION DE L'USINE ( CONSTRUCTION OU UPRADE ).
--# idLabo PERMET DE RETROUVER LES UNITÉS LABOS POUR APPLIQUER LES MODIFS RECH.
--# NIVEAU TECH DE LA RECHERCHE EFFECTUÉE PERMET DE POINTER UN DES NIVEAUX TECHS DE USINE
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

	ActualiserNiveauVeteranUsine = function( self )

		local idArmee = self.Sync.army  --# NE TRAITER QUE LES USINES DE LA MÊME ARMÉE

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return  end  --# POUR CONTROLE ULTÉRIEUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return  end  --# SIGNALER ABSENCE DE NIVEAU TECH ?

		--# LISTE VIDE => CAS OÙ LISTE (RÉ)INITIALISÉES ( VOIR EN HAUT DE PAGE )
		if  table.getsize( ListeSyncLabos ) <= 0  then
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  ActualiserNiveauVeteranUsine  :  LISTE SYNC VIDE => FIN DE FONCTION  POUR ARMÉE ' .. tostring(self.Sync.army) .. '  !!!  ListeSyncLabos = ' .. repr(ListeSyncLabos) .. ' ' )
			return false  --# LISTE SYNC NON INITIALISÉE !!!
		end

		local idLabo = false

		--# POUR TROUVER LE LABO DONT ARMEE, TYPE ET TECH CORRESPONSENT !!!
		for index, uneSync in ipairs( ListeSyncLabos ) do
			if   uneSync.id     and  uneSync.id != nil
			and  uneSync.army  and  uneSync.army != nil  and  uneSync.army == self.Sync.army
			and  uneSync.type   and  uneSync.type != nil   and  uneSync.type == typeBatiment
			and  uneSync.tech   and  uneSync.tech != nil   and  uneSync.tech == niveauTech  then
				idLabo = uneSync.id  --# RÉCUP ID LAB0 DANS ListeSyncLabos
				break
			end
		end

		--# LISTE SYNC LABOS NON INITIALISÉE => IMPOSSIBLE DE CONTINUER !!!
		if  idLabo == nil  then
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  ActualiserNiveauVeteranUsine  :  LISTE SYNC LABOS NON INITIALISÉE => IMPOSSIBLE DE CONTINUER !!! !!!  ListeSyncLabos = ' .. repr(ListeSyncLabos) .. ' ' )
			return false
		end

		--# ID LABO NON RÉPERTORIÉ DANS LA LISTE => RIEN À EXPLOITER !!!
		if  EstUnBooleen( idLabo )  and  idLabo == false  then  --# LABO PAS OBLIGATOIREMENT CONSTRUIT 
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  ActualiserNiveauVeteranUsine  :  ID LABO NON RÉPERTORIÉ DANS LA LISTE => RIEN À EXPLOITER !!!  ListeSyncLabos = ' .. repr(ListeSyncLabos) .. ' ' )
			return false
		end

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  ActualiserNiveauVeteranUsine  :  idLabo = ' .. tostring(idLabo) .. '  POUR JOUEUR  [ARMY' .. tostring(self.Sync.army) .. '][' .. tostring(nomType[typeBatiment]) .. '][TECH' .. tostring(niveauTech) .. ']'  )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		if  idLabo  and  idLabo != ""  then  --# LABO PAS OBLIGATOIREMENT CONSTRUIT !
			local zeLAB = GetUnitById( idLabo )   --# LE LABO !

			if  zeLAB != false  and  zeLAB != nil  and  not zeLAB:IsDead()
			and  idArmee == zeLAB.Sync.army  then  --# LABO PAS OBLIGATOIREMENT CONSTRUIT !

				local niveauTechLabo = IndexTechUnite( zeLAB )
				local niveauDeRecherche = self.RecupNiveauDeRechercheDansLabo( self, zeLAB )
				--# M à J de NiveauxVeteran  ( CONTIENT UN NIV. DE RECHERCHE PAR NIV. TECH )
				self.NiveauxVeteran[niveauTechLabo] = niveauDeRecherche
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  ActualiserNiveauVeteranUsine  :  LABO RETROUVÉ  zeLAB.Sync.id = ' .. tostring(zeLAB.Sync.id) .. '  DE NIVEAU TECH = ' .. tostring(niveauTechLabo) .. '  =>  NIVEAU RECHERCHE = ' .. tostring(niveauDeRecherche) .. '  self.NiveauxVeteran = ' .. repr(self.NiveauxVeteran) .. '' )
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			end
		end  --# END IF  idLabo

	end,


--[[
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--# NOTE DE MANIMAL :
--# NE PAS SIGNALER ERREURS CAR LABO PAS FORCÉMENT CONSTRUIT OU BIEN DÉTRUIT !!!
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

	FixerNouveauNiveauVeteranUsine = function( self )

		local niveauTechUsine = IndexTechUnite( self )

		--# NiveauxVeteran CONTIENT UN NIVEAU DE RECHERCHE PAR NIVEAU TECH
		local niveauVeteran = self.NiveauxVeteran[niveauTechUsine]

		if  niveauVeteran  and  niveauVeteran > 0  then
			local numKills = self:GetStat( 'KILLS', 0 ).Value
			if  numKills > 0 then
				self:SetStat( 'KILLS', 0 )
			end
			self:SetVeterancy( niveauVeteran ) --# MODIFIE LE NOMBRE DE KILLS !!! => JAMAIS MONTRÉ POUR USINES !
		end

	end,


	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


--[[
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--# NOTE DE MANIMAL :
--# FORCER KILLS SUR ZÉRO ALORS QUE KILLS EST DÉJÀ ÉGAL À ZÉRO => PLANTAGE DU JEU !!!
--# R.À.Z DU NBR DE KILLS À CAUSE DU CUMUL DES KILLS VIA LES NIVEAUX VÉTERAN PRÉCÉDENTS
--# VIA UPGRADE SINON FAUSSE COMPLÈTEMENT LE NIVEAU VÉTERAN ET REND LE JEU INSTABLE !!!
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

	FixerNiveauVeteranUsineSurUnite = function( self, unite )
		if  unite == nil  or  unite == false  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
		if  self.Sync.army != unite.Sync.army  then  return false  end  --# CETTE ARMÉE UNIQUEMENT !

		local niveauTechUnite = IndexTechUnite( unite )

		--# NiveauxVeteran CONTIENT UN NIVEAU DE RECHERCHE PAR NIVEAU TECH
		local niveauVeteran = self.NiveauxVeteran[niveauTechUnite]

		if  niveauVeteran  and  niveauVeteran > 0  then
			local numKills = unite:GetStat( 'KILLS', 0 ).Value
			if  numKills > 0 then
				unite:SetStat( 'KILLS', 0 )
			end
			unite:SetVeterancy( niveauVeteran ) --# MODIFIE LE NOMBRE DE KILLS !!! => JAMAIS MONTRÉ POUR USINES !
		end  --# SIGNALER ABSENCE DE MODIFS ?

	end,


	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    OnCreate = function( self )
        StructureUnit.OnCreate( self )

	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# AJOUT PAR MANIMAL : 
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		self.idPereDeUsine = false      --# POUR OnStartBuild
		self.NiveauxVeteran = { 0, 0, 0, 0 } --# 4 NIV TECH
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    end,


--[[
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	#  MODIF PAR MANIMAL :
	#  POUR MISE À JOUR DES DONNÉES USINE
	#  N.B: CERTAINES INFOS PEUVENT ÊTRE PASSÉES À FactoryUnit VIA builder !
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]--

	OnStartBeingBuilt = function( self, builder, layer )
		StructureUnit.OnStartBeingBuilt(  self, builder, layer  )
		--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		--# AJOUT PAR MANIMAL : 
		--# INITIALISER MODIFS PAR RECHERCHE, UTILISÉ PAR LE LABO
		--# self.NiveauxVeteran : LISTE DES RECHERCHES
		--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		if  builder  and  builder != nil  and  not builder:IsDead()  then
			if  EntityCategoryContains( catCmndr, builder )  then
				self.idPereDeUsine = builder.Sync.id
			else
				self.idPereDeUsine = builder.idPereDeUsine
			end  --# END IF  EntityCategoryContains
		end  --# END IF  builder

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( '\n\nMANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  OnStartBeingBuilt  :  PERE USINE self -> idPereDeUsine = ' .. tostring(self.idPereDeUsine) .. '  (type = ' .. type(self.idPereDeUsine) .. ')   Sync.army = ' .. tostring(self.Sync.army) .. '  (type = ' .. type(self.Sync.army) .. ')' )
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  OnStartBeingBuilt  :  PERE USINE builder -> Sync.id = ' .. tostring(builder.Sync.id) .. '  (type = ' .. type(builder.Sync.id) .. ')   Sync.army = ' .. tostring(builder.Sync.army) .. '  (type = ' .. type(builder.Sync.army) .. ')' )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	end,  --# END OnStartBeingBuilt


--[[
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	#  MODIF PAR MANIMAL :
	#  POUR MISE À JOUR DES DONNÉES USINE
	#  N.B: CERTAINES INFOS PEUVENT ÊTRE PASSÉES À FactoryUnit VIA builder !
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]--

    OnStopBeingBuilt = function( self, builder, layer )
        StructureUnit.OnStopBeingBuilt( self, builder, layer )

		--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		--# AJOUT PAR MANIMAL :  METTRE À JOUR LA LISTE DES RECHERCHES !
		--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		local fractionComplete = self:GetFractionComplete()
		if  fractionComplete == 1  then  --# ASSURANCE QUE UPGRADE EST TERMINÉ
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  OnStopBeingBuilt  :  PERE USINE builder -> Sync.id = ' .. tostring(builder.Sync.id) .. '  (type = ' .. type(builder.Sync.id) .. ')   Sync.army = ' .. tostring(builder.Sync.army) .. '  (type = ' .. type(builder.Sync.army) .. ')' )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			self.AjouterIdUniteDansListeSyncUsines( self )

			--# SI USINE CONSTRUITE APRÈS FIN DE RECHERCHE => NON ACTUALISÉE PAR LABO
			self.ActualiserNiveauVeteranUsine( self )
			self.FixerNouveauNiveauVeteranUsine( self )  --# MODIFIE LE NOMBRE DE KILLS !!!
		end  --# IF  FRACTION COMPLETE
		--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    end,  --# END OnStopBeingBuilt



--[[
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--# MODIF PAR MANIMAL :
--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

    OnStartBuild = function( self, unitBeingBuilt, order )
        StructureUnit.OnStartBuild( self, unitBeingBuilt, order )

	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# ACTUALISER MODIFS PAR RECHERCHE AVANT CHAQUE CONSTRUCTION D'UNITÉ
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( '\n\nMANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  OnStartBuild  :  PERE USINE self -> idPereDeUsine = ' .. tostring(self.idPereDeUsine) .. '  (type = ' .. type(self.idPereDeUsine) .. ')   Sync.army = ' .. tostring(self.Sync.army) .. '  (type = ' .. type(self.Sync.army) .. ')' )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		local zePERE = false
		if  self.idPereDeUsine != nil  and  self.idPereDeUsine != false  then
			zePERE = GetUnitById( self.idPereDeUsine )
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  OnStartBuild  :  zePERE -> Sync.id = ' .. tostring(zePERE.Sync.id) .. '  (type = ' .. type(zePERE.Sync.id) .. ')   Sync.army = ' .. tostring(zePERE.Sync.army) .. '  (type = ' .. type(zePERE.Sync.army) .. ')' )
		end
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    end,


--[[
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# BUG FIX BY MANIMAL :
	# I NOTICED THAT MANY CLASSES DO NOT DEFIME OnStopBuild THE SAME WAY FOR MOST OF THE FACTORIES
	# WHEN OnStopBuild IS FIRED FROM AIR AND/OR NAVAL FACTORY UNITS, THE VALUE OF order IS nil !!!
	# THE PROBLEM LIES WITHIN xxxxunits.lua (xxxx = faction name) THAT DEFINES UNCONSISTENTLY OnStopBuild
	# FOR AIR + SEA + SUB FactoryUnit CLASSES, THAT DOES NOT MATCH AT ALL THE DEFINITION OF GENERIC FactoryUnit WITHIN defaultunits.lua !!!
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# J'AI REMARQUÉ QUE PLUSIEURS CLASSES DÉFINISSENT OnStopBuild DIFFÉREMMENT POUR LA PLUPART DES USINES
	# PENDANT LA CONSTRUCTION D'UNITÉS AIR ET/OU NAVAL, LA VALEUR DE order EST nil !!!
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

--[[
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# MODIF PAR MANIMAL :
	# MISE À JOUR UNITÉ EN FONCTION DES RECHERCHES EFFECTUÉES 
	# APPLIQUER MODIFS RECHERCHÉES À PARTIR DE MODIFICATEURS PRÉSENTS DANS Builder
	# ACTUELLEMENT, ACTION LIMITÉE À Veteran Level !!!  À DÉVELOPPER POUR AUTRES CAS
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

    OnStopBuild = function( self, unitBeingBuilt, order )
        StructureUnit.OnStopBuild( self, unitBeingBuilt, order  )
        
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		local selfUnId = self:GetUnitId()
		local uBBid = unitBeingBuilt:GetUnitId()
		LOG(  'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  VFU  ->  OnStopBuild  :  ' .. tostring( selfUnId ) .. '  ORDRE = ' .. tostring( order ) .. '  ' .. tostring( uBBid ) .. ' !'   )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		local fractionComplete = self:GetFractionComplete()

		if  fractionComplete == 1  then  --# ASSURANCE QUE UPGRADE EST TERMINÉ

			if  order  and  order == 'FactoryBuild'  then

				if  unitBeingBuilt:GetFractionComplete() == 1  then  --# CONSTRUCTION UNITÉ TERMINÉE
					self.FixerNiveauVeteranUsineSurUnite( self, unitBeingBuilt )
				end  --# IF  UNITBEINGBUILT

			end  --# IF  ORDER

		end  --# IF  FRACTION COMPLETE

    end,  --# END OnStopBuild


    OnDestroy = function( self )

		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		--# METTRE À JOUR LA LISTE DES RECHERCHES DU LABO !
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		self.RetirerIdUniteDansListeSyncUsines( self, self, ListeSyncUsines )

        StructureUnit.OnDestroy( self )

    end,


}




################################################################################
#
#  FACTORY UNIT - SCRIPT DE MANIMAL
#
################################################################################


FactoryUnit = Class( VeteranFactoryUnit ) {


    OnCreate = function( self )
        VeteranFactoryUnit.OnCreate( self )
        self.BuildingUnit = false
    end,


    OnPaused = function( self )
        --# When factory is paused take some action
        self:StopUnitAmbientSound(  'ConstructLoop'  )
        VeteranFactoryUnit.OnPaused( self )
    end,

    OnUnpaused = function( self )
        if self.BuildingUnit then
            self:PlayUnitAmbientSound(  'ConstructLoop'  )
        end
        VeteranFactoryUnit.OnUnpaused( self )
    end,


	OnStartBeingBuilt = function( self, builder, layer )
		VeteranFactoryUnit.OnStartBeingBuilt(  self, builder, layer  )
	end,


    OnStopBeingBuilt = function( self, builder, layer )
        local aiBrain = GetArmyBrain( self:GetArmy() )
        aiBrain:ESRegisterUnitMassStorage( self )
        aiBrain:ESRegisterUnitEnergyStorage( self )
        local curEnergy = aiBrain:GetEconomyStoredRatio( 'ENERGY' )
        local curMass = aiBrain:GetEconomyStoredRatio( 'MASS' )
        if curEnergy > 0.11 and curMass > 0.11 then
            self:CreateBlinkingLights( 'Green' )
            self.BlinkingLightsState = 'Green'
        else
            self:CreateBlinkingLights( 'Red' )
            self.BlinkingLightsState = 'Red'
        end
        VeteranFactoryUnit.OnStopBeingBuilt( self, builder, layer )

	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# AJOUT PAR MANIMAL : 
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		--local fractionComplete = self:GetFractionComplete()

		--if  fractionComplete == 1  then  --# ASSURANCE QUE UPGRADE EST TERMINÉ

		--end  --# IF  FRACTION COMPLETE
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    end,  --# END OnStopBeingBuilt


    ChangeBlinkingLights = function( self, state )
        local bls = self.BlinkingLightsState
        if state == 'Yellow' then
            if bls == 'Green' then
                self:CreateBlinkingLights( 'Yellow' )
                self.BlinkingLightsState = state
            end
        elseif state == 'Green' then
            if bls == 'Yellow' then
                self:CreateBlinkingLights( 'Green' )
                self.BlinkingLightsState = state
            elseif bls == 'Red' then
                local aiBrain = GetArmyBrain( self:GetArmy() )
                local curEnergy = aiBrain:GetEconomyStoredRatio( 'ENERGY' )
                local curMass = aiBrain:GetEconomyStoredRatio( 'MASS' )
                if curEnergy > 0.11 and curMass > 0.11 then
                    if self:GetNumBuildOrders( categories.ALLUNITS ) == 0 then
                        self:CreateBlinkingLights( 'Green' )
                        self.BlinkingLightsState = state
                    else
                        self:CreateBlinkingLights( 'Yellow' )
                        self.BlinkingLightsState = 'Yellow'
                    end
                end
            end
        elseif state == 'Red' then
            self:CreateBlinkingLights( 'Red' )
            self.BlinkingLightsState = state
        end
    end,

    OnMassStorageStateChange = function( self, newState )
        if newState == 'EconLowMassStore' then
            self:ChangeBlinkingLights( 'Red' )
        else
            self:ChangeBlinkingLights( 'Green' )
        end
    end,

    OnEnergyStorageStateChange = function( self, newState )
        if newState == 'EconLowEnergyStore' then
            self:ChangeBlinkingLights( 'Red' )
        else
            self:ChangeBlinkingLights( 'Green' )
        end
    end,


    OnStartBuild = function( self, unitBeingBuilt, order )
        self:ChangeBlinkingLights( 'Yellow' )
        VeteranFactoryUnit.OnStartBuild( self, unitBeingBuilt, order )
        self.BuildingUnit = true
        if order != 'Upgrade' then
            ChangeState(  self, self.BuildingState  )
            self.BuildingUnit = false
        end
        self.FactoryBuildFailed = false
    end,


    OnStopBuild = function( self, unitBeingBuilt, order )
        VeteranFactoryUnit.OnStopBuild( self, unitBeingBuilt, order  )
        
        if not self.FactoryBuildFailed then
            if not EntityCategoryContains( categories.AIR, unitBeingBuilt ) then 
                self:RollOffUnit()
            end
            self:StopBuildFx()
            self:ForkThread( self.FinishBuildThread, unitBeingBuilt, order  )
        end
        self.BuildingUnit = false
    end,


    FinishBuildThread = function( self, unitBeingBuilt, order )
        self:SetBusy( true )
        self:SetBlockCommandQueue( true )
        local bp = self:GetBlueprint()
        local bpAnim = bp.Display.AnimationFinishBuildLand
        if bpAnim and EntityCategoryContains( categories.LAND, unitBeingBuilt ) then
            self.RollOffAnim = CreateAnimator( self ):PlayAnim( bpAnim )
            self.Trash:Add( self.RollOffAnim )
            WaitTicks( 1 )
            WaitFor( self.RollOffAnim )
        end
        if unitBeingBuilt and not unitBeingBuilt:IsDead() then
            unitBeingBuilt:DetachFrom( true )
        end
        self:DetachAll( bp.Display.BuildAttachBone or 0 )
        self:DestroyBuildRotator()
        if order != 'Upgrade' then
            ChangeState( self, self.RollingOffState )
        else
            self:SetBusy( false )
            self:SetBlockCommandQueue( false )
        end
    end,


    CheckBuildRestriction = function( self, target_bp )
        if self:CanBuild( target_bp.BlueprintId ) then
            return true
        else
            return false
        end
    end,

    OnFailedToBuild = function( self )
        self.FactoryBuildFailed = true        
        VeteranFactoryUnit.OnFailedToBuild( self )
        self:DestroyBuildRotator()
        self:StopBuildFx()
        ChangeState( self, self.IdleState )
    end,

    CalculateRollOffPoint = function( self )
        local bp = self:GetBlueprint().Physics.RollOffPoints
        local px, py, pz = unpack( self:GetPosition() )
        if not bp then return 0, px, py, pz end
        local vectorObj = self:GetRallyPoint()
        local bpKey = 1
        local distance, lowest = nil
        for k, v in bp do
            distance = VDist2( vectorObj[1], vectorObj[3], v.X + px, v.Z + pz )
            if not lowest or distance < lowest then
                bpKey = k
                lowest = distance
            end
        end
        local fx, fy, fz, spin
        local bpP = bp[bpKey]
        local unitBP = self.UnitBeingBuilt:GetBlueprint().Display.ForcedBuildSpin
        if unitBP then
            spin = unitBP
        else
            spin = bpP.UnitSpin
        end
        fx = bpP.X + px
        fy = bpP.Y + py
        fz = bpP.Z + pz
        return spin, fx, fy, fz
    end,

    RollOffUnit = function( self )
        local spin, x, y, z = self:CalculateRollOffPoint()
        local units = { self.UnitBeingBuilt }
        self.MoveCommand = IssueMove( units, Vector( x, y, z ) )
    end,

    StartBuildFx = function( self, unitBeingBuilt )
    end,

    StopBuildFx = function( self )
    end,

    PlayFxRollOff = function( self )
    end,

    PlayFxRollOffEnd = function( self )
        if self.RollOffAnim then        
            self.RollOffAnim:SetRate( -1 )
            WaitFor( self.RollOffAnim )
            self.RollOffAnim:Destroy()
            self.RollOffAnim = nil
        end
    end,

    CreateBuildRotator = function( self )
        if not self.BuildBoneRotator then
            local spin = self:CalculateRollOffPoint()
            local bp = self:GetBlueprint().Display
            self.BuildBoneRotator = CreateRotator( self, bp.BuildAttachBone or 0, 'y', spin, 10000 )
            self.Trash:Add( self.BuildBoneRotator )
        end
    end,

    DestroyBuildRotator = function( self )
        if self.BuildBoneRotator then
            self.BuildBoneRotator:Destroy()
            self.BuildBoneRotator = nil
        end
    end,

    RolloffBody = function( self )
        self:SetBusy( true )
        self:SetBlockCommandQueue( true )
        self:PlayFxRollOff()
        # Wait Until unit has left the factory
        while not self.UnitBeingBuilt:IsDead() and self.MoveCommand and not IsCommandDone( self.MoveCommand ) do
            WaitSeconds( 0.5 )
        end
        self.MoveCommand = nil
        self:PlayFxRollOffEnd()
        self:SetBusy( false )
        self:SetBlockCommandQueue( false )
        ChangeState( self, self.IdleState )
    end,

    IdleState = State {

        Main = function( self )
            self:ChangeBlinkingLights( 'Green' )
            self:SetBusy( false )
            self:SetBlockCommandQueue( false )
            self:DestroyBuildRotator()
        end,
    },

    BuildingState = State {

        Main = function( self )
            local unitBuilding = self.UnitBeingBuilt
            local bp = self:GetBlueprint()
            local bone = bp.Display.BuildAttachBone or 0
            self:DetachAll( bone )
            unitBuilding:AttachBoneTo( -2, self, bone )
            self:CreateBuildRotator()
            self:StartBuildFx( unitBuilding )
        end,
    },

    RollingOffState = State {
        Main = function( self )
            self:RolloffBody()
        end,
    },


    OnKilled = function( self, instigator, type, overkillRatio )
        VeteranFactoryUnit.OnKilled( self, instigator, type, overkillRatio )

		if self.UnitBeingBuilt and not self.UnitBeingBuilt:IsDead() and self.UnitBeingBuilt:GetFractionComplete() != 1 then
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			--# MUDIF PAR MANIMAL :
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            --# DO WHAT YOU NEED THERE
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        end
    end,


}




################################################################################
#
#  USINES SOUS-MARINES /  SUB FACTORY UNITS DEFINTIONS
#
################################################################################

#-------------------------------------------------------------
#  SUB FACTORY UNITS
#  These units typically float under the water and have wake when they move.
#-------------------------------------------------------------

SubFactoryUnit = Class( VeteranFactoryUnit ) {

    # use default spark effect Until underwater damaged states are made
    FxDamage1 = {EffectTemplate.DamageSparks01},
    FxDamage2 = {EffectTemplate.DamageSparks01},
    FxDamage3 = {EffectTemplate.DamageSparks01},

    # DESTRUCTION PARAMS
    PlayDestructionEffects = true,
    ShowUnitDestructionDebris = false,
    DeathThreadDestructionWaitTime = 0,


	OnCreate = function( self )
        VeteranFactoryUnit.OnCreate( self )
        self.BuildingUnit = false
    end,


    OnPaused = function( self )
        --# When factory is paused take some action
        self:StopUnitAmbientSound( 'ConstructLoop' )
        VeteranFactoryUnit.OnPaused( self )
    end,

    OnUnpaused = function( self )
        if self.BuildingUnit then
            self:PlayUnitAmbientSound( 'ConstructLoop' )
        end
        VeteranFactoryUnit.OnUnpaused( self )
    end,


    OnStartBeingBuilt = function( self, builder, layer )
        VeteranFactoryUnit.OnStartBeingBuilt(  self, builder, layer  )
    end,


    OnStopBeingBuilt = function( self, builder, layer )
        VeteranFactoryUnit.OnStopBeingBuilt( self, builder, layer )
    end,


    ChangeBlinkingLights = function( self, state )
        local bls = self.BlinkingLightsState
        if state == 'Yellow' then
            if bls == 'Green' then
                self:CreateBlinkingLights( 'Yellow' )
                self.BlinkingLightsState = state
            end
        elseif state == 'Green' then
            if bls == 'Yellow' then
                self:CreateBlinkingLights( 'Green' )
                self.BlinkingLightsState = state
            elseif bls == 'Red' then
                local aiBrain = GetArmyBrain( self:GetArmy() )
                local curEnergy = aiBrain:GetEconomyStoredRatio( 'ENERGY' )
                local curMass = aiBrain:GetEconomyStoredRatio( 'MASS' )
                if  curEnergy > 0.11  and  curMass > 0.11  then
                    if  self:GetNumBuildOrders( categories.ALLUNITS ) == 0  then
                        self:CreateBlinkingLights( 'Green' )
                        self.BlinkingLightsState = state
                    else
                        self:CreateBlinkingLights( 'Yellow' )
                        self.BlinkingLightsState = 'Yellow'
                    end
                end
            end
        elseif state == 'Red' then
            self:CreateBlinkingLights( 'Red' )
            self.BlinkingLightsState = state
        end
    end,

    OnMassStorageStateChange = function( self, newState )
        if newState == 'EconLowMassStore' then
            self:ChangeBlinkingLights( 'Red' )
        else
            self:ChangeBlinkingLights( 'Green' )
        end
    end,

    OnEnergyStorageStateChange = function( self, newState )
        if newState == 'EconLowEnergyStore' then
            self:ChangeBlinkingLights( 'Red' )
        else
            self:ChangeBlinkingLights( 'Green' )
        end
    end,


    OnStartBuild = function( self, unitBeingBuilt, order )
        VeteranFactoryUnit.OnStartBuild( self, unitBeingBuilt, order )
    end,


    OnStopBuild = function( self, unitBeingBuilt, order )
        VeteranFactoryUnit.OnStopBuild( self, unitBeingBuilt, order )
    end,


    FinishBuildThread = function( self, unitBeingBuilt, order )
        self:SetBusy( true )
        self:SetBlockCommandQueue( true )
        local bp = self:GetBlueprint()
        local bpAnim = bp.Display.AnimationFinishBuildLand
        if bpAnim and EntityCategoryContains( categories.LAND, unitBeingBuilt ) then
            self.RollOffAnim = CreateAnimator( self ):PlayAnim( bpAnim )
            self.Trash:Add( self.RollOffAnim )
            WaitTicks( 1 )
            WaitFor( self.RollOffAnim )
        end
        if unitBeingBuilt and not unitBeingBuilt:IsDead() then
            unitBeingBuilt:DetachFrom( true )
        end
        self:DetachAll( bp.Display.BuildAttachBone or 0 )
        self:DestroyBuildRotator()
        if order != 'Upgrade' then
            ChangeState( self, self.RollingOffState )
        else
            self:SetBusy( false )
            self:SetBlockCommandQueue( false )
        end
    end,


	CheckBuildRestriction = function( self, target_bp )
		local MaxBuiltNumber = target_bp.MaxBuiltNumber or 99999
		local brain = self:GetAIBrain()
		if self:CanBuild( target_bp.BlueprintId ) and brain:GetArmyStat( "Units_Active_" .. target_bp.BlueprintId,  0.0 ).Value <= MaxBuiltNumber then
			return true
		else
			return false
		end
	end,


    OnFailedToBuild = function( self )
        self.FactoryBuildFailed = true        
        VeteranFactoryUnit.OnFailedToBuild( self )
        self:DestroyBuildRotator()
        self:StopBuildFx()
        ChangeState( self, self.IdleState )
    end,


    RollOffUnit = function( self )
        local spin, x, y, z = self:CalculateRollOffPoint()
        local units = { self.UnitBeingBuilt }
        self.MoveCommand = IssueMove(  units, Vector( x, y, z )  )
    end,

    CalculateRollOffPoint = function( self )
        local bp = self:GetBlueprint().Physics.RollOffPoints
        local px, py, pz = unpack( self:GetPosition() )
        if not bp then return 0, px, py, pz end
        local vectorObj = self:GetRallyPoint()
        local bpKey = 1
        local distance, lowest = nil
        for k, v in bp do
            distance = VDist2( vectorObj[1], vectorObj[3], v.X + px, v.Z + pz )
            if not lowest or distance < lowest then
                bpKey = k
                lowest = distance
            end
        end
        local fx, fy, fz, spin
        local bpP = bp[bpKey]
        local unitBP = self.UnitBeingBuilt:GetBlueprint().Display.ForcedBuildSpin
        if unitBP then
            spin = unitBP
        else
            spin = bpP.UnitSpin
        end
        fx = bpP.X + px
        fy = bpP.Y + py
        fz = bpP.Z + pz
        return spin, fx, fy, fz
    end,


    StartBuildFx = function( self, unitBeingBuilt )
    end,

    StopBuildFx = function( self )
    end,

    PlayFxRollOff = function( self )
    end,

    PlayFxRollOffEnd = function( self )
        if self.RollOffAnim then        
            self.RollOffAnim:SetRate( -1 )
            WaitFor( self.RollOffAnim )
            self.RollOffAnim:Destroy()
            self.RollOffAnim = nil
        end
    end,


    CreateBuildRotator = function( self )
        if not self.BuildBoneRotator then
            local spin = self:CalculateRollOffPoint()
            local bp = self:GetBlueprint().Display
            self.BuildBoneRotator = CreateRotator( self, bp.BuildAttachBone or 0, 'y', spin, 10000 )
            self.Trash:Add( self.BuildBoneRotator )
        end
    end,

    DestroyBuildRotator = function( self )
        if self.BuildBoneRotator then
            self.BuildBoneRotator:Destroy()
            self.BuildBoneRotator = nil
        end
    end,


    RolloffBody = function( self )
        self:SetBusy( true )
        self:SetBlockCommandQueue( true )
        self:PlayFxRollOff()
        # Wait Until unit has left the factory
        while not self.UnitBeingBuilt:IsDead() and self.MoveCommand and not IsCommandDone( self.MoveCommand ) do
            WaitSeconds( 0.5 )
        end
        self.MoveCommand = nil
        self:PlayFxRollOffEnd()
        self:SetBusy( false )
        self:SetBlockCommandQueue( false )
        ChangeState( self, self.IdleState )
    end,


    IdleState = State {

        Main = function( self )
            self:ChangeBlinkingLights( 'Green' )
            self:SetBusy( false )
            self:SetBlockCommandQueue( false )
            self:DestroyBuildRotator()
        end,
    },

    BuildingState = State {

        Main = function( self )
            local unitBuilding = self.UnitBeingBuilt
            local bp = self:GetBlueprint()
            local bone = bp.Display.BuildAttachBone or 0
            self:DetachAll( bone )
            unitBuilding:AttachBoneTo( -2, self, bone )
            self:CreateBuildRotator()
            self:StartBuildFx( unitBuilding )
        end,
    },


    RollingOffState = State {
        Main = function( self )
            self:RolloffBody()
        end,
    },


    OnKilled = function( self, instigator, type, overkillRatio)
		self:DestroyIdleEffects()
		#local layer = self:GetCurrentLayer()
		#local bp = self:GetBlueprint()

        VeteranFactoryUnit.OnKilled( self, instigator, type, overkillRatio)
    end,

}



################################################################################
#
#  HOOKS CRÉANT LES NOUVEAUX DefaultUnits
#
################################################################################


#-------------------------------------------------------------
#  LAND FACTORY UNIT
#-------------------------------------------------------------

LandFactoryUnit = Class( FactoryUnit ) {}


#-------------------------------------------------------------
#  AIR FACTORY UNIT
#-------------------------------------------------------------

AirFactoryUnit = Class( FactoryUnit ) {}


#-------------------------------------------------------------
#  NAVAL FACTORY UNIT
#-------------------------------------------------------------

SeaFactoryUnit = Class( FactoryUnit ) {}


#-------------------------------------------------------------
#  QUANTUM GATE UNIT
#-------------------------------------------------------------

QuantumGateUnit = Class( FactoryUnit ) {}



################################################################################
#
#  LABO STRUCTURE - SCRIPT DE MANIMAL
#
################################################################################

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AVERTISSEMENT :
# LE LABO, SES RECHERCHES ET LES USINES SONT LIÉS.
# NE PAS MODIFIER CE SCRIPT SANS EN AVOIR COMPRIS LE FONCTIONNEMENT,
# CAR RISQUE DE PLANTER LE JEU.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# WARNING:
# DO NOT ALTER THIS SCRIPT UNLESS YOU KNOW WHAT YOU'RE DOING (GAME WOULD CRASH)
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--[[
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# POUR CRÉATION DE UnitBlueprint DU LABO DE RECHERCHE VETERAN :
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# UTILISER  Categories.'RECHERCHE'  ET  Categories.'VETERAN'
# DE PLUS IL EXISTE DÉJÀ UNE LISTE DANS LE LABO ACTUEL :
# EXEMPLE DE RECHERCHE POUR VeteranLevel 4:
# CetteRecherche = {
# 	nomDeRecherche = 'VETERAN',
# 	niveauDeRecherche = 4,
# },
#
# UN AJOUT DE NOUVELLE CATEGORIE RECHERCHE SE FAIT VIA UN NOM EXISTANT.
# Exemple: VETERAN est le nom d'une caracteristique existante + son niveau
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]]--



LaboStructureUnit = Class( StructureUnit ) {

	--# ~~~~~~~~~~~~~~~~~~~~
	--# INIT
	--# ~~~~

	Upgrading = false,

	idPerePremierLabo = false,  --# INDISPENSABLE POUR OnDestroy 
	LaboKilled = false,
	LaboReclaimed = false,

	--# NE PAS ACCÈDER À ModifieParRecherche VIA AUTRE UNITÉ CAR PAS SYNCHRO !!!
	ModifieParRecherche = {},   --# INFOS ISSUES DU BLUEPRINT DU LABO

	--# ~~~~~~~~~~~~~~~~~~~~

    OnCreate = function( self )
        StructureUnit.OnCreate( self )

		self.ResearchEffectsBag = TrashBag()

		self.LaboKilled = false
		self.LaboReclaimed = false

		--# NE PAS ACCÈDER À ModifieParRecherche VIA AUTRE UNITÉ CAR PAS SYNCHRO !!!
		self.ModifieParRecherche = UneRechercheParDefaut

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		local message = '\n\nMANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnCreate  :  '

		if IsUnit( self ) and EstUneEntiteUnique( self ) and EstUnLabo( self ) then
			local idUnite = self:GetUnitId() or "UNITE INCONNUE"
			local idEntite = self.Sync.id or "IDENTIF. INCONNUE"
			local armee = self:GetArmy()

			message = message .. 'EstUneEntiteUnique'
			if EstNonCapturable( self ) then
				self:SetCapturable( false )
				message = message .. '  EstNonCapturable'
			end
			message = message .. '\nMANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnCreate  :  armee = ' .. tostring(armee) .. '  UnitId Labo = '.. tostring(idUnite) .. '  SyncId Labo = '.. tostring(self.Sync.id) .. '\n'
		end
		LOG( message )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    end,


    OnPaused = function( self )
        self:SetActiveConsumptionInactive()
		if self:IsUnitState( 'Upgrading' ) then
			self:StopUnitAmbientSound( 'EnhanceLoop' )
		end
    end,


    OnUnpaused = function( self )
		self:SetActiveConsumptionActive()
		if self:IsUnitState( 'Upgrading' ) then
			self:PlayUnitAmbientSound( 'EnhanceLoop' )
		end
    end,


    ChangeBlinkingLights = function( self, state )
        local bls = self.BlinkingLightsState
        if state == 'Yellow' then
            if bls == 'Green' then
                self:CreateBlinkingLights( 'Yellow' )
                self.BlinkingLightsState = state
            end
        elseif state == 'Green' then
            if bls == 'Yellow' then
                self:CreateBlinkingLights( 'Green' )
                self.BlinkingLightsState = state
            elseif bls == 'Red' then
                local aiBrain = GetArmyBrain( self:GetArmy() )
                local curEnergy = aiBrain:GetEconomyStoredRatio( 'ENERGY' )
                local curMass = aiBrain:GetEconomyStoredRatio( 'MASS' )
                if curEnergy > 0.11 and curMass > 0.11 then
                    if self:GetNumBuildOrders( categories.ALLUNITS ) == 0 then
                        self:CreateBlinkingLights( 'Green' )
                        self.BlinkingLightsState = state
                    else
                        self:CreateBlinkingLights( 'Yellow' )
                        self.BlinkingLightsState = 'Yellow'
                    end
                end
            end
        elseif state == 'Red' then
            self:CreateBlinkingLights( 'Red' )
            self.BlinkingLightsState = state
        end
    end,


    OnMassStorageStateChange = function( self, newState )
        if newState == 'EconLowMassStore' then
            self:ChangeBlinkingLights( 'Red' )
        else
            self:ChangeBlinkingLights( 'Green' )
        end
    end,


    OnEnergyStorageStateChange = function( self, newState )
        if newState == 'EconLowEnergyStore' then
            self:ChangeBlinkingLights( 'Red' )
        else
            self:ChangeBlinkingLights( 'Green' )
        end
    end,


	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# FONCTIONS GÉNÉRALES DU LABO :
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	PasseAuNiveauTechSuivant = function( self, unite, constructeur )  --# 
		if  not unite  or  unite == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
		if  not constructeur  or  constructeur == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

		local niveauTechConstr = IndexTechUnite( constructeur )
		local niveauTechUnite = IndexTechUnite( unite )
		return ( niveauTechUnite > niveauTechConstr )
	end,


	RestreindreConstructionDeLaboUniqueVeteran = function( self, labo, constructeur )
		if  not labo  or  labo == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
		if  not constructeur  or  constructeur == nil  then  return false  end  --# POUR CONTROLE ULTÉRIEUR

		local catType = CategorieTypeUnite( labo )
		local catTech = CategorieTechUnite( labo )
		local catLaboConstruit = catType * catTech * ( catLabo + catVeteran + catUnique )
		RestreindreConstructionParCategorie( constructeur, catLaboConstruit )
	end,


	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# NOTE DE MANIMAL : GESTION DE LISTE SYNC LABOS ( POUR USINES OU INGÉS )
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	IndexIdUniteDansListeSyncLabos = function( self )

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return false  end  --# POUR GESTION ERREUR

		--# CAS OÙ LISTE (RÉ)INITIALISÉES ( VOIR EN HAUT DE PAGE )
		if  table.getsize( ListeSyncLabos ) <= 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  IndexIdUniteDansListeSyncLabos  :  LISTE SYNC VIDE POUR ARMÉE ' .. tostring(self.Sync.army) .. '  !!!  ListeSyncLabos = ' .. repr(ListeSyncLabos) .. ' ' )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false  --# LISTE SYNC VIDE !!!
		end

		for index, uneSync in ipairs( ListeSyncLabos ) do
			if   uneSync.id     and  uneSync.id != nil     and  uneSync.id == self.Sync.id
			and  uneSync.army  and  uneSync.army != nil  and  uneSync.army == self.Sync.army
			and  uneSync.type   and  uneSync.type != nil   and  uneSync.type == typeBatiment
			and  uneSync.tech   and  uneSync.tech != nil   and  uneSync.tech == niveauTech  then
				return index  --# POUR ACCÈS RAPIDE À ID UNITÉ DANS ListeSyncLabos
			end
		end

		return 0  --# SIGNALER ZÉRO ÉLÉMENTS TROUVÉS
	end,


	AjouterIdUniteDansListeSyncLabos = function( self )

		local idArmee = self.Sync.army  --# POUR TRAITER UNITÉ PAR ARMÉE

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return false  end  --# POUR GESTION ERREUR

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AjouterIdUniteDansListeSyncLabos  :  UNITE ' .. tostring(self:GetUnitId()) .. '  ID ' .. tostring(self.Sync.id) .. ' ARMEE ' .. tostring(self.Sync.army) .. '  [' .. nomType[typeBatiment] .. '][TECH' .. tostring(niveauTech) ..  ']' )
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AjouterIdUniteDansListeSyncLabos  :  LISTE SYNC  AVANT = ' .. repr(ListeSyncLabos) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		local indexUnite = self.IndexIdUniteDansListeSyncLabos( self )

		--# FONCTION MAL UTILISÉE => VÉRIFIER LE SCRIPT !!!
		if  indexUnite == nil  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AjouterIdUniteDansListeSyncLabos  :  FONCTION IndexIdUniteDansListeSyncLabos MAL UTILISÉE => VÉRIFIER LE SCRIPT !!!' )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		##### CONTROLE DU SCRIPT EN COURS DE DEVELOPPEMENT #####  SUPPRIMER ENSUITE
		--# LISTE SYNC VIDE => AUCUN PROBLEME !!! ( CONTROLE DU SCRIPT EN COURS DE DEVELOPPEMENT )
		if  EstUnBooleen( indexUnite )  and  indexUnite == false  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AjouterIdUniteDansListeSyncLabos  :  LISTE SYNC VIDE => AUCUN PROBLEME !!!    ListeSyncLabos = ' .. repr(ListeSyncLabos) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		end

		##### CONTROLE DU SCRIPT EN COURS DE DEVELOPPEMENT #####  SUPPRIMER ENSUITE
		--# ID NON RÉPERTORIÉ => AUCUN PROBLEME !!! ( CONTROLE DU SCRIPT EN COURS DE DEVELOPPEMENT )
		if  EstUnNombre( indexUnite )  and  indexUnite == 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AjouterIdUniteDansListeSyncLabos  :  ID UNITE NON REPERTORIE => AUCUN PROBLEME !!!    ListeSyncLabos = ' .. repr(ListeSyncLabos) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		end

		--# ID UNITÉ TROUVÉ ! ( => ÉCRASER CET ÉLÉMENT ? )
		if  EstUnNombre( indexUnite )  and  indexUnite > 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AjouterIdUniteDansListeSyncLabos  :  ID UNITE TROUVE !!!    ListeSyncLabos = ' .. repr(ListeSyncLabos) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		local nouveauLabo = {
				army = self.Sync.army,
				id = self.Sync.id,
				bpid = self:GetUnitId(),
				type = typeBatiment,
				tech = niveauTech
		}

		--# INSÉRER DANS LISTE DES ID USINES
		table.insert( ListeSyncLabos, nouveauLabo ) --# TRANSFERT ID LAB0

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AjouterIdUniteDansListeSyncLabos  :  ListeSyncLabos  APRES = ' .. repr(ListeSyncLabos) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		return true  --# POUR GESTION ERREUR
	end,


	RetirerIdUniteDansListeSyncLabos = function( self )

		local idArmee = self.Sync.army  --# POUR TRAITER UNITÉ PAR ARMÉE

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return false  end  --# POUR GESTION ERREUR

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  RetirerIdUniteDansListeSyncLabos  :  UNITE ' .. tostring(self:GetUnitId()) .. '  id ' .. tostring(self.Sync.id) .. ' ARMEE ' .. tostring(self.Sync.army) .. '  [' .. nomType[typeBatiment] .. '][TECH' .. tostring(niveauTech) ..  ']' )
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  RetirerIdUniteDansListeSyncLabos  :  ListeSyncLabos  AVANT = ' .. repr(ListeSyncLabos) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		local indexUnite = self.IndexIdUniteDansListeSyncLabos( self )

		--# LISTE SYNC NON INITIALISÉE => REVOIR UTILISATION DE LA FONCTION IndexIdUniteDansListeSyncLabos !!!
		if  indexUnite == nil  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  RetirerIdUniteDansListeSyncLabos  :  LISTE SYNC NON INITIALISEE => REVOIR UTILISATION DE LA FONCTION IndexIdUniteDansListeSyncLabos    ListeSyncLabos = ' .. repr(ListeSyncLabos) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		--# LISTE SYNC VIDE => RIEN À RETIRER DE LA LISTE !!!
		if  EstUnBooleen( indexUnite )  and  indexUnite == false  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  RetirerIdUniteDansListeSyncLabos  :  LISTE SYNC VIDE => RIEN A RETIRER DE LA LISTE !!!    EstUnBooleen( indexUnite ) = ' .. tostring(EstUnBooleen(indexUnite)) .. ' (type = ' .. type(EstUnBooleen(indexUnite)).. ')  #  ListeSyncLabos = ' .. repr(ListeSyncLabos) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		--# ID UNITÉ NON RÉPERTORIÉ => RIEN À RETIRER DE LA LISTE !!!
		if  EstUnNombre( indexUnite )  and  indexUnite == 0  then
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  RetirerIdUniteDansListeSyncLabos  :  ID UNITE NON REPERTORIE => RIEN A RETIRER DE LA LISTE !!!    EstUnBooleen( indexUnite ) = ' .. tostring(EstUnBooleen(indexUnite)) .. ' (type = ' .. type(EstUnBooleen(indexUnite)).. ')  #  ListeSyncLabos = ' .. repr(ListeSyncLabos) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end

		--# ID UNITÉ TROUVÉ => RETIRER ID UNITÉ DE LA LISTE !
		if  EstUnNombre( indexUnite )  and  indexUnite > 0  then
			table.remove( ListeSyncLabos, indexUnite )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  RetirerIdUniteDansListeSyncLabos  :   ID UNITÉ REPERTORIE !!!  ListeSyncLabos  APRES  = ' .. repr(ListeSyncLabos) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		end

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  RetirerIdUniteDansListeSyncLabos  :   VERIF  ListeSyncLabos  APRES  = ' .. repr(ListeSyncLabos) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		return true  --# POUR GESTION ERREUR
	end,


	IdUniteDejaConstruite = function( self )
		--# LISTE SYNC VIDE => PAS DE PROBLÈME CAR LABO PAS DÉJÀ CONSTRUIT !!!
		if  table.getsize( ListeSyncLabos ) <= 0  then 
			return false
		end

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		--# TROUVER LABO DE MÊME ARMÉE ET DE MÊME TYPE
		for index, uneSync in ipairs( ListeSyncLabos ) do
			if   uneSync.id     and  uneSync.id != nil
			and  uneSync.army  and  uneSync.army != nil  and  uneSync.army == self.Sync.army
			and  uneSync.type   and  uneSync.type != nil   and  uneSync.type == typeBatiment  then
				return uneSync.id
			end
		end

		return false
	end,


	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# FONCTIONS SPÉCIFIQUES AUX RECHERCHES :
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	InfosDeLaRecherche = function( self )

		local infosDeRecherche = false

		--# DÉTERMINER SI DEMANDEUR EST LABO / RECHERCHE  (OU BIEN USINE, ETC)
		if EntityCategoryContains( catLabo, self ) then
			local bp = self:GetBlueprint() or false
			if  bp == false  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
			if  bp.CetteRecherche == nil  or  bp.CetteRecherche == false  or  table.getsize( bp.CetteRecherche ) <= 0  then  return false  end  --# POUR CONTROLE ULTÉRIEUR
			infosDeRecherche = {
				nomDeRecherche = bp.CetteRecherche.nomDeRecherche,
				niveauDeRecherche = bp.CetteRecherche.niveauDeRecherche,
			}
		end

		if  not infosDeRecherche  or  infosDeRecherche == nil  or  table.getsize( infosDeRecherche ) <= 0  then
			WARN( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  InfosDeLaRechercheDansLabo  :  ERREUR: infosDeRecherche (' .. type( infosDeRecherche ) .. '), DEVRAIT UNE TABLE NON VIDE !\n'  )
			infosDeRecherche = false
		end

		return infosDeRecherche
	end,


	NomDeLaRecherche = function( self )

		local infosDeRecherche = self.InfosDeLaRecherche( self )
		local nomDeRecherche = false

		if  infosDeRecherche  then
			nomDeRecherche = infosDeRecherche.nomDeRecherche
		end

		return nomDeRecherche
	end,


	NiveauDeLaRecherche = function( self )

		local infosDeRecherche = self.InfosDeLaRecherche( self )
		local niveauDeRecherche = false

		if  infosDeRecherche  then
			niveauDeRecherche = infosDeRecherche.niveauDeRecherche
		end

		return niveauDeRecherche
	end,


    OnStartResearch = function( self, uniteArech, initiateur )
    end,


    OnStopResearch = function( self, uniteArech, initiateur )
    end,


--[[ 
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# NOTE DE MANIMAL :
	--# RECHERCHE INEXISTANTE CAR BATIMENT NOUVELLEMENT CONSTRUIT OU AMÉLIORÉ
	--# => MISE À JOUR OU CRÉATION DES INFOS DE LA RECHERCHE EFFECTUÉE !!!
	--# NIVEAU TECH DE RECHERCHE FAITE PERMET DE POINTER UN NIVEAU TECH DE USINE
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

	ActualiserNiveauRechercheLabo = function( self )
		self.ModifieParRecherche = self.InfosDeLaRecherche( self )
	end,


--[[
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# NOTE DE MANIMAL :
	--# LE NIVEAU DE RECHERCHE LABO DOIT AVOIR ÉTÉ PRÉALABLEMENT ACTUALISÉ
	--# FORCER KILLS SUR ZÉRO ALORS QUE KILLS EST DÉJÀ ÉGAL À ZÉRO => PLANTAGE DU JEU !!!
	--# R.À.Z DU NBR DE KILLS À CAUSE DU CUMUL DES KILLS VIA LES NIVEAUX VÉTERAN PRÉCÉDENTS
	--# VIA UPGRADE SINON FAUSSE COMPLÈTEMENT LE NIVEAU VÉTERAN ET REND LE JEU INSTABLE !!!
	--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

	FixerNouveauNiveauVeteranLabo = function( self )

		local niveauDeRecherche = self.ModifieParRecherche.niveauDeRecherche

		if  niveauDeRecherche  and  niveauDeRecherche > 0  then
			local numKills = self:GetStat( 'KILLS', 0 ).Value
			if  numKills > 0 then
				self:SetStat( 'KILLS', 0 )
			end
			self:SetVeterancy( niveauDeRecherche ) --# MODIFIE LE NOMBRE DE KILLS !!! => JAMAIS MONTRÉ POUR USINES !
		end

	end,


--[[
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	--# NOTE DE MANIMAL :
	--# MISE À JOUR DIRECTE DU NIVEAU VÉTÉRAN USINES (OU INGÉS) VIA LISTES SYNC
	--# LE NIVEAU DE RECHERCHE LABO DOIT AVOIR ÉTÉ PRÉALABLEMENT ACTUALISÉ
	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--
	--[[ 
		ListeSyncExemple =  {
			{
				army = number,
				id = string,
				type = number,
				tech = number
			},
		}
	]]--

	AppliquerRechercheSurUsines = function( self )

		local idArmee = self.Sync.army  --# NE TRAITER QUE LES USINES DE LA MÊME ARMÉE

		local typeBatiment = IndexTypeUnite( self )
		if  typeBatiment == false  then  return false  end  --# POUR GESTION ERREUR

		local niveauTech = IndexTechUnite( self )
		if  niveauTech == false  then  return false  end  --# POUR GESTION ERREUR

		--# LISTE SYNC VIDE => AUCUNE ACTION POSSIBLE !!!
		if  table.getsize( ListeSyncUsines ) <= 0  then 
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AppliquerRechercheSurUsines  :  LISTE SYNC VIDE => FIN DE FONCTION  POUR ARMÉE ' .. tostring(idArmee) .. '  TYPE  ' .. tostring(typeBatiment) .. '  TECH' .. tostring(niveauTech) .. ' !!!  ListeSyncUsines = ' .. repr(ListeSyncUsines) .. ' ' )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			return false
		end  --# POUR GESTION ERREUR

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AppliquerRechercheSurUsines  :  ListeSyncUsines  ARMEE ' .. tostring(idArmee) .. '  ' .. nomType[typeBatiment] .. '  TECH ' .. tostring(niveauTech) .. '  = ' .. repr(ListeSyncUsines) .. ' (type = ' .. type(ListeSyncUsines) .. ')' )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		--# SCAN TOUTES USINES !!! ( PAS DE break ! )
		for index, uneSync in ipairs( ListeSyncUsines ) do

			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AppliquerRechercheSurUsines  :  uneSync = ' .. repr(uneSync) .. '  uneSync.id ' .. tostring(uneSync.id) .. '  uneSync.army ' .. tostring(uneSync.army) .. '  uneSync.type = ' .. tostring(uneSync.type) .. ' = ' .. nomType[uneSync.type] .. '  uneSync.tech' .. tostring(uneSync.tech) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			local unsSyncOK = false


			if  uneSync.id and ( uneSync.id != nil )
			and  uneSync.army and ( uneSync.army != nil ) and ( uneSync.army == self.Sync.army )
			and  uneSync.type and ( uneSync.type != nil ) and ( uneSync.type == typeBatiment )
			and  uneSync.tech and ( uneSync.tech != nil ) and ( uneSync.tech == niveauTech )  then

				local uneUsine = GetUnitById( uneSync.id )

				if  uneUsine != nil  and  uneUsine != false and  not uneUsine:IsDead()  then

					local niveauDeRecherche = self.NiveauDeLaRecherche( self ) --# NIVEAU VÉTÉRAN DU LABO

					if  niveauDeRecherche  and  niveauDeRecherche > 0  then
						uneUsine.NiveauxVeteran[niveauTech] = niveauDeRecherche

						#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
						LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  AppliquerRechercheSurUsines  :  niveauDeRecherche = ' .. tostring(niveauDeRecherche) .. '  SUR  uneUsine ' .. tostring(uneUsine:GetUnitId()) .. '  ID ' .. tostring(uneUsine.Sync.id) .. '  ARMEE ' .. tostring(idArmee) .. '  [' .. nomType[typeBatiment] .. '][TECH' .. tostring(niveauTech) ..  '] #' )
						#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

						local numKills = uneUsine:GetStat( 'KILLS', 0 ).Value
						if  numKills > 0 then
							uneUsine:SetStat( 'KILLS', 0 )
						end

						uneUsine:SetVeterancy( niveauDeRecherche ) --# MODIFIE LE NOMBRE DE KILLS !!! => JAMAIS MONTRÉ POUR USINES !
					end
				end  --# END IF uneUsine

			end  --# END IF uneSyncId
		end  --# END FOR

		return true  --# POUR GESTION ERREUR

	end,  --# END AppliquerRechercheSurUsines


    OnResearchCompleted = function( self, uniteArech, initiateur )
		--uniteArech  : Labo En Cours de Construction
		--initiateur : Labo Initiateur Upgrade
		#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		### À FAIRE : RETROUVER LA RECHERCHE EXACTE ( 'VETERAN', ETC )
		#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		if  uniteArech == nil  or  uniteArech == false  then  return false  end
		if  initiateur == nil  or  initiateur == false  then  return false  end

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		local selfUnId = self:GetUnitId()
		local recUid = uniteArech:GetUnitId()
		local iniUid = initiateur:GetUnitId()
		local nomRecherche = self.NomDeLaRecherche( uniteArech )
		if  nomRecherche == false  then  return false  end
		local niveauRecherche = self.NiveauDeLaRecherche( uniteArech )
		if  niveauRecherche == false  then  return false  end
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnResearchCompleted  :  Labo  ' .. tostring(selfUnId) .. '  >  RECHERCHE EN COURS [' .. nomRecherche .. ']  DE NIVEAU [' .. tostring(niveauRecherche) .. ']  PAR  [' .. tostring(iniUid) .. ']  >  REUSSIE ! '  )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		self.ActualiserNiveauRechercheLabo( self )

		self.FixerNouveauNiveauVeteranLabo( self ) --# MODIFIE LE NOMBRE DE KILLS !!!

		self.AppliquerRechercheSurUsines( self )

   end,


	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# FIN DES FONCTIONS SPÉCIFIQUES AUX RECHERCHES :
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    OnStartBeingBuilt = function( self, builder, layer )

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		local idUniteBuilder = builder:GetUnitId() or "UNITE INCONNUE"

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBeingBuilt  :  CONSTRUCTION DE LABO '.. tostring(idUnite) .. '  PAR  ' .. tostring(idUniteBuilder) .. '  SUR  ' .. tostring(layer) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		--# NOTIFICATION DU CONSTRUCTEUR ( UBC )
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		if  builder  and  builder != nil  and  not builder:IsDead()  then

			local idArmee = self.Sync.army  --# POUR TRAITER UNITÉ PAR ARMÉE

			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBeingBuilt  :  PREMIER LABO VERIF  LaboReInit = ' .. repr(LaboReInit) )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			--# 1 ÈRE CONSTRUCTION / RECONSTRUCTION
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			if  EntityCategoryContains( catCmndr, builder )  then

				local laboBpid = false

				--# RETROUVER LE LABO À RECONSTRUIRE. SUPPOSE QUE LaboReInit À ÉTÉ INITIALISÉ CORRECTEMENT
				--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				for index, unLabo in ipairs( LaboReInit ) do
					if unLabo != nil  and  unLabo.army == idArmee  and  unLabo.bpid == idUnite  then
						laboBpid = unLabo.bpid
						break
					end
				end

				if  laboBpid == false  then  --# 1 ÈRE CONSTRUCTION PAR UBC DE TOUS NIVEAUX
					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBeingBuilt  :  EST PREMIERE CONSTRUCTION  laboBpid ' .. tostring(laboBpid) .. '  ARMEE ' .. tostring(idArmee) .. '  LaboReInit = ' .. repr(LaboReInit)  )
					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

				elseif  laboBpid != false  and  laboBpid != nil  then  --# RECONSTRUCTION
					local catBpIdLaboReconstruit = CategorieIdUnite( laboBpid )
					RestreindreConstructionParCategorie( builder, catBpIdLaboReconstruit ) --# ASSURER LA RESTRICTION

					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBeingBuilt  :  EST RECONSTRUCTION DE  ' .. tostring(laboBpid) .. '  ARMEE ' .. tostring(idArmee) .. '  LaboReInit = ' .. repr(LaboReInit)  )
					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				end

				self.RestreindreConstructionDeLaboUniqueVeteran( self, self, builder )

				--# NOTIFICATION DE RESTRICTION DU LABO DEJA CONSTRUIT
				--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				local idLaboDejaConstruit = self.IdUniteDejaConstruite( self )
				if  idLaboDejaConstruit != false  then
					local zeLaboDejaConstruit = GetUnitById( idLaboDejaConstruit )
					if  zeLaboDejaConstruit != nil  and  zeLaboDejaConstruit != false  and  not zeLaboDejaConstruit:IsDead()  then
						local catTechLaboEnCoursDeConstr = CategorieTechUnite( self )
						RestreindreConstructionParCategorie( zeLaboDejaConstruit, catTechLaboEnCoursDeConstr ) --# ASSURER LA RESTRICTION
					end
				end

				self.idPerePremierLabo = builder.Sync.id  --# INDISPENSABLE POUR OnDestroy

				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBeingBuilt  :  TRANSFERT ID LABO (  PREMIERE CONSTRUCTION / RECONSTRUCTION ) !' )
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			--# UPGRADE
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			elseif  EntityCategoryContains( catLabo, builder )  then

				--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				--# NOTE DE MANIMAL :
				--# NOUVELLE RESTRICTION IMPOSÉE PAR ASDRUBAEL
				--# ENPÊCHER UBC DE CONSTRUIRE LABO DE NIV TECH ACTUEL
				--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				if  self.PasseAuNiveauTechSuivant( self, self, builder ) == true  then
					local zeUBC = GetUnitById( builder.idPerePremierLabo )
					if  zeUBC != nil  and  zeUBC != false and  not zeUBC:IsDead()  then
						self.RestreindreConstructionDeLaboUniqueVeteran( self, self, zeUBC )
					end
				end

				self.idPerePremierLabo = builder.idPerePremierLabo  --# INDISPENSABLE POUR OnDestroy

				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBeingBuilt  :  TRANSFERT ID LABO ( UPGRADE ) !'  )
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			end  --# END IF  EntityCategoryContains

			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBeingBuilt  :   Pere du Labo = ' .. tostring(self.idPerePremierLabo)  )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		end  --# END IF  builder

		StructureUnit.OnStartBeingBuilt( self, builder, layer )
    end,


    OnStopBeingBuilt = function( self, builder, layer )

        local aiBrain = GetArmyBrain( self:GetArmy() )
        aiBrain:ESRegisterUnitMassStorage( self )
        aiBrain:ESRegisterUnitEnergyStorage( self )
        local curEnergy = aiBrain:GetEconomyStoredRatio( 'ENERGY' )
        local curMass = aiBrain:GetEconomyStoredRatio( 'MASS' )
        if curEnergy > 0.11 and curMass > 0.11 then
            self:CreateBlinkingLights( 'Green' )
            self.BlinkingLightsState = 'Green'
        else
            self:CreateBlinkingLights( 'Red' )
            self.BlinkingLightsState = 'Red'
        end
        StructureUnit.OnStopBeingBuilt( self, builder, layer )

		--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        self:SetMaintenanceConsumptionActive()

		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		local idUniteBuilder = builder:GetUnitId() or "UNITE INCONNUE"

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStopBeingBuilt  :  CONSTRUCTION DE LABO '.. tostring(idUnite) .. '  PAR  ' .. tostring(idUniteBuilder) .. '  SUR  ' .. tostring(layer) )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		--# ~~~~~~~~~~~~~~~~~~~~~~~~
		--# (RE)CONSTRUCTION ACHEVÉE
		--# ~~~~~~~~~~~~~~~~~~~~~~~~
		local fractionComplete = self:GetFractionComplete()

		if  fractionComplete == 1  then  --# ASSURANCE QUE UPGRADE / RECONSTRUCTION EST TERMINÉ

			local idArmee = self.Sync.army  --# NE TRAITER QUE LES LABOS DE LA MÊME ARMÉE

			--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			--# RéINIT DES RECONSTRUCTIONS
			--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			if  EntityCategoryContains( catCmndr, builder )  then

				local indexLabo = false
				--# RETROUVER LE LABO RECONSTRUIT. SUPPOSE QUE LaboReInit À ÉTÉ INITIALISÉ CORRECTEMENT
				for index, unLabo in ipairs( LaboReInit ) do
					if  unLabo  and  unLabo != nil  and  unLabo.army == idArmee  and  unLabo.bpid == idUnite  then
						indexLabo = index
						break
					end
				end
				--# SUPPRIMER LE LABO RECONSTRUIT.
				if  indexLabo != false  and  indexLabo > 0  then
					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStopBeingBuilt  :  LABO  RECONSTRUIT ID = ' .. tostring(self.Sync.id) .. ' ARMY ' .. tostring(idArmee) .. '  INDEX = ' .. tostring(indexLabo) .. '  LaboReInit AVANT MODIF = ' .. repr(LaboReInit)  )
					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					table.remove( LaboReInit, indexLabo ) --# R à Z
				end

				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStopBeingBuilt  :  VERIF  LABO ID = ' .. tostring(self.Sync.id) .. ' ARMY ' .. tostring(idArmee) .. '  LaboReInit = ' .. repr(LaboReInit)  )
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			end  --# END  IF  EntityCategoryContains

			--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			--# ENREGISTREMENT DE LA RECHERCHE
			--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStopBeingBuilt  :  CONTROLE AVANT MODIF  ListeSyncLabos = ' .. repr(ListeSyncLabos)  )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			self.AjouterIdUniteDansListeSyncLabos( self )  --# TRANSFERT ID LAB0

			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStopBeingBuilt  :  CONTROLE APRES MODIF  ListeSyncLabos = ' .. repr(ListeSyncLabos)  )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

			self.OnResearchCompleted( self, self, builder )  --# SIGNALER RECHERCHE TERMINEE !

			end  --# END IF fractionComplete

	--#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    end,


    OnStartBuild = function( self, unitBeingBuilt, order )

		--# LES LABOS NE CONSTRUISENT RIEN !!!
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		if order != 'Upgrade' then  return  end

		self.Upgrading = false

		--# REPRISE PARTIELLE DU CODE DE Unit.OnStartBuild
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        self:DoOnStartBuildCallbacks( unitBeingBuilt )
        self:SetActiveConsumptionActive()

        self.UnitBeingBuilt = unitBeingBuilt

		local bp = self:GetBlueprint() or false
		if  not bp  or  not bp.General.UpgradesTo  then  return false  end
		local upgradesToUnitId = bp.General.UpgradesTo
		local unitBeingBuiltId = unitBeingBuilt:GetUnitId()

		if  unitBeingBuiltId == upgradesToUnitId  and  order == 'Upgrade'  then
			self.Upgrading = true
			unitBeingBuilt.DisallowCollisions = true

			if unitBeingBuilt:GetBlueprint().Physics.FlattenSkirt and not unitBeingBuilt:HasTarmac() then
				if self.TarmacBag and self:HasTarmac() then
					unitBeingBuilt:CreateTarmac(true, true, true, self.TarmacBag.Orientation, self.TarmacBag.CurrentBP )
				else
					unitBeingBuilt:CreateTarmac(true, true, true, false, false)
				end
			end           

			self:ChangeBlinkingLights( 'Yellow' )  # AJOUTER AU LABO des VOYANTS CLIGNOTANTS  OU un BuildEffect ?

			ChangeState( self, self.UpgradingState )

			--# TRAITER LES RECHERCHES DU LABO
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			if  EstUneRecherche( unitBeingBuilt ) == true  then
				self.OnStartResearch( self, unitBeingBuilt, self )  # SIGNALER RECHERCHE COMMENCÉE !
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStartBuild  :  LABO ACTION = RECHERCHE LANCEE !\n'  )
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			end
		end
    end,


--[[
	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# REMARQUE DE MANIMAL : OnStopBuild
	# SHUNTÉ PAR UpgradingState.OnStopBuild !
	# ACTIF SI UpgradingState.OnFailedToBuild
	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--
--[[
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# BUG FIX BY MANIMAL :
	# I NOTICED THAT MANY CLASSES DO NOT DEFIME OnStopBuild THE SAME WAY FOR MOST OF THE FACTORIES
	# WHEN OnStopBuild IS FIRED FROM AIR AND/OR NAVAL FACOTRY UNITS, THE VALUE OF order IS nil !!!
	# THE PROBLEM SITS WITHIN xxxxunits.lua (xxxx = FACTION NAME) THAT DEFINES UNCONSISTENTLY OnStopBuild
	# FOR AIR + SEA + SUB FactoryUnit CLASSES, THAT DOES NOT MATCH AT ALL THE DEFINITION OF GENERIC FactoryUnit within defaultunits.lua !!!
	# J'AI REMARQUÉ QUE PLUSIEURS CLASSES DÉFINISSENT OnStopBuild DIFFÉREMMENT POUR LA PLUPART DES USINES
	# PENDANT LA CONSTRUCTION D'UNITÉS AIR ET/OU NAVAL, LA VALEUR DE order ESR nil !!!
	#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--


    OnStopBuild = function( self, unitBeingBuilt, order )


        --# LES LABOS NE CONSTRUISENT RIEN !!!
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		if order != 'Upgrade' then  return  end

		--# REPRISE PARTIELLE DU CODE DE Unit.OnStopBuild
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        self:SetActiveConsumptionInactive()
        self:DoOnUnitBuiltCallbacks(unitBeingBuilt)

		--# TRAITER LES AMÉLIORATIONS DU LABO # SHUNTÉ PAR UpgradingState.OnStopBuild !
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		local bp = self:GetBlueprint() or false
		if  bp == false then  return false  end
		local unitid = bp.General.UpgradesTo

		local selfUnId = self:GetUnitId()
		local ubbId = self.UnitBeingBuilt:GetUnitId()

		if  ubbId == unitid  and  order == 'Upgrade'  then # SHUNTÉ PAR UpgradingState.OnStopBuild !
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStopBuild  :  AMELIORATION  DE ' .. tostring(selfUnId) .. ' EN ' .. tostring(ubbId) .. ' TERMINEE !'  )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			--# TRAITER LES RECHERCHES DU LABO
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			if  EstUneRecherche( unitBeingBuilt ) == true  then  --# LE LABO TERMINE LA RECHERCHE !!!
				self.OnStopResearch( self, unitBeingBuilt, self )  --# SIGNALER RECHERCHE INTERROMPUE !

				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
				LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnStopBuild  :  LABO ACTION = RECHERCHE TERMINÉE !\n'  )
				#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			end
		end

		self.Upgrading = false
    end,


	--# EN CAS D'UPGRADE INTERROMPU 
    OnFailedToBuild = function( self )
        --self.LaboratoryBuildFailed = true  --# self.FactoryBuildFailed = true  NE S'APPLIQUE PAS AUX LABOS
        --Unit.OnFailedToBuild( self )    --# StructureUnit.OnFailedToBuild( self )  NE S'APPLIQUE PAS AUX LABOS
        self:DestroyBuildRotator()
        self:StopBuildFx()
        ChangeState( self, self.IdleState )
    end,


    CheckBuildRestriction = function( self, target_bp )

        if self:CanBuild( target_bp.BlueprintId ) then
            return true
        else
            return false
        end
    end,


    OnReclaimed = function( self, entity )

		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		local idUnite = self:GetUnitId() or "UNITE INCONNUE"
		local idEntity = entity:GetUnitId() or "UNITE INCONNUE"
		LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnReclaimed  : UNITE RECYCLEE ' .. tostring(idUnite) .. '  PAR  ' .. tostring(idEntity) .. '\n'  )
		#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        if  self.UnitBeingBuilt  and  not self.UnitBeingBuilt:IsDead()
        and  self.UnitBeingBuilt:GetFractionComplete() != 1  then

			--# POUR GARANTIR QUE UBC NE VERRA PAS UnitBeingBuilt COMME UNITÉ À RECONSTRUIRE :
			--# SI BESOIN ACTIVER self.UnitBeingBuilt.idPerePremierLabo = false 

			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local ubbId = self.UnitBeingBuilt:GetUnitId()
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnReclaimed  :  RECYCLAGE DU LABO ' .. tostring(idUnite) .. ' AVEC SA RECHERCHE EN COURS ' .. tostring(ubbId) .. ' !!!\n' )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        end

		self.LaboReclaimed = true

        StructureUnit.OnReclaimed( self, entity )
    end,


    OnKilled = function( self, instigator, type, overkillRatio )

        if  self.UnitBeingBuilt  and  self.UnitBeingBuilt != nil  and  not self.UnitBeingBuilt:IsDead()
        and  self.UnitBeingBuilt:GetFractionComplete() != 1  then
			--# POUR GARANTIR QUE UBC NE VERRA PAS UnitBeingBuilt COMME UNITÉ À RECONSTRUIRE :
			--# SI BESOIN ACTIVER self.UnitBeingBuilt.idPerePremierLabo = false 

			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local uniteId = self:GetUnitId()
			local ubbId = self.UnitBeingBuilt:GetUnitId()
			local tueurId = "UNITE NON IDENTIFIEE ( OU CTRL-K ) !!!"
			if  instigator  and  instigator != nil  then
				tueurId = instigator:GetUnitId()
			end
			LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnKilled  :  LABO ' .. tostring(uniteId) .. '  TUE PAR  ' .. tostring(tueurId) .. '  AVEC SA RECHERCHE EN COURS ' .. tostring(ubbId) .. ' !!!\n' )
			#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        end

		self.LaboKilled = true

        StructureUnit.OnKilled( self, instigator, type, overkillRatio )
    end,


--[[
	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# NOTE DE MANIMAL : AUCUN OnDestroy DANS DefaultUnits.StructureUnit ORIGINAL !
	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

    OnDestroy = function( self )  --NE FONCTIONNE PAS ICI :  self:IsUnitState( 'Upgrading' )

		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		--# NOTE DE MANIMAL :
		--# LE LABO DOIT DEVENIR RECONSTRUCTIBLE ! ( MAIS PAS SON UPGRADE INACHEVÉ )
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

		if  self.LaboKilled == true  or  self.LaboReclaimed == true  then

			--# NOTIFICATION DU CONSTRUCTEUR ( UBC )
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local zeUBC = false

			if  self.idPerePremierLabo != false  and  self.idPerePremierLabo != nil  then
				zeUBC = GetUnitById( self.idPerePremierLabo )
			end

			--# AUTORISER LA RECONSTRUCTION DU LABO MORT !
			--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			local idArmee = self.Sync.army  --# NE TRAITER QUE LES USINES DE LA MÊME ARMÉE

			local indexTypeUnite = IndexTypeUnite( self )  --# INDISPENSABLE POUR RECONSTRUIRE

			if  indexTypeUnite  and  indexTypeUnite > 0  then

				if  zeUBC != false  and  zeUBC != nil  and  not zeUBC:IsDead()  and  idArmee == zeUBC.Sync.army  then

					local uniteId = self:GetUnitId()

					local catLaboDetruit = CategorieIdUnite( uniteId )  -- DÉBLOQUER LE LABO DÉTRUIT UNIQUEMENT
					--zeUBC:RemoveBuildRestriction( catLaboDetruit )
					--zeUBC:RequestRefreshUI()
					PermettreConstructionParCategorie( zeUBC, catLaboDetruit )

					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnDestroy  :  VERIF  AVANT  uniteId = ' .. tostring(uniteId) .. '  indexTypeUnite = ' .. nomType[indexTypeUnite] .. '  self.idPerePremierLabo = ' .. tostring(self.idPerePremierLabo) .. '  zeUBC.LaboReInit = ' .. repr(zeUBC.LaboReInit)  )
					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

					local infoLabo = {  --# INDISPENSABLE POUR RECONSTRUIRE
						army = self.Sync.army,
						bpid = uniteId
					}

					--# ENREGISTRER LE LABO À RECONSTRUIRE. SUPPOSE QUE LaboReInit À ÉTÉ INITIALISÉ CORRECTEMENT
					table.insert( LaboReInit, infoLabo )

					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
					LOG( 'MANIMAL TRACEUR  /hook/lua/EW_DefaultUnits.lua  LSU  ->  OnDestroy  :  VERIF  APRES  uniteId = ' .. tostring(uniteId) .. '  indexTypeUnite = ' .. nomType[indexTypeUnite] .. '  self.idPerePremierLabo = ' .. tostring(self.idPerePremierLabo) .. '  zeUBC.LaboReInit = ' .. repr(zeUBC.LaboReInit)  )
					#~~~~~ TRACEURS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

				end  --#  END IF  zeUBC

			end  --#  END IF  indexTypeUnite

		end  --# END IF  self.LaboKilled  OR  self.LaboReclaimed 

		--# METTRE À JOUR LA LISTE DES RECHERCHES DU LABO !
		--# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		self.RetirerIdUniteDansListeSyncLabos( self )

		if  self.ResearchEffectsBag  then
			self.ResearchEffectsBag:Destroy()
		end

        StructureUnit.OnDestroy( self )
    end,


--[[
    ##########################################################################################
    ## STATES
    ##########################################################################################
]]--

    IdleState = State {
        Main = function( self )
            self:ChangeBlinkingLights( 'Green' )
            self:SetBusy( false )
            self:SetBlockCommandQueue( false )
        end,
    },


--[[
	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	# NOTE DE MANIMAL : 
	# SURCHARGE INDISPENDABLE DE StructureUnit.UpgradingState ORIGINAL !
	# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~]]--

    UpgradingState = State {

        Main = function( self )
            self:StopRocking()
            local bp = self:GetBlueprint().Display
            self:DestroyTarmac()
            self:PlayUnitSound('UpgradeStart')
            self:DisableDefaultToggleCaps()
            if bp.AnimationUpgrade then
                local unitBuilding = self.UnitBeingBuilt
                self.AnimatorUpgradeManip = CreateAnimator( self )
                self.Trash:Add( self.AnimatorUpgradeManip )
                local fractionOfComplete = 0
                self:StartUpgradeEffects( unitBuilding )
                self.AnimatorUpgradeManip:PlayAnim( bp.AnimationUpgrade, false ):SetRate(0)

                while fractionOfComplete < 1 and not self:IsDead() do
                    fractionOfComplete = unitBuilding:GetFractionComplete()
                    self.AnimatorUpgradeManip:SetAnimationFraction( fractionOfComplete )
                    WaitTicks( 1 )
                end
                if not self:IsDead() then
                    self.AnimatorUpgradeManip:SetRate( 1 )
                end
            end
        end,

        OnStopBuild = function( self, unitBuilding )
			self:SetActiveConsumptionInactive()
			self:DoOnUnitBuiltCallbacks( unitBuilding )
            self:EnableDefaultToggleCaps()
            
            if unitBuilding:GetFractionComplete() == 1 then
                NotifyUpgrade( self, unitBuilding )
                self:StopUpgradeEffects( unitBuilding )
                self:PlayUnitSound('UpgradeEnd')
                self:Destroy()
            end
        end,

        OnFailedToBuild = function( self )
            Unit.OnFailedToBuild( self )    --StructureUnit.OnFailedToBuild( self )
            self:EnableDefaultToggleCaps()
            
            if self.AnimatorUpgradeManip then
				self.AnimatorUpgradeManip:Destroy()
			end
            
            if self:GetCurrentLayer() == 'Water' then
                self:StartRocking()
            end
            self:PlayUnitSound('UpgradeFailed')
            self:PlayActiveAnimation()
            self:CreateTarmac( true, true, true, self.TarmacBag.Orientation, self.TarmacBag.CurrentBP )
            ChangeState( self, self.IdleState )
        end,

    },


}



#-------------------------------------------------------------
#  LAND RESEARCH LAB UNIT
#-------------------------------------------------------------

LandResearchLabUnit = Class( LaboStructureUnit ) {}


#-------------------------------------------------------------
#  AIR RESEARCH LAB UNIT
#-------------------------------------------------------------

AirResearchLabUnit = Class( LaboStructureUnit ) {}


#-------------------------------------------------------------
#  NAVAL UNIT RESEARCH LAB
#-------------------------------------------------------------

NavalResearchLabUnit = Class( LaboStructureUnit ) {}




#######################  FIN DE  EW_DefaultUnits.lua  #######################

