if not unit.GetHealthPercentage then unit.GetHealthPercentage = function (id) return object.GetHealthInfo(id).valuePercents end end
if not unit.IsFriend then unit.IsFriend = object.IsFriend end
if not unit.IsEnemy then unit.IsEnemy = object.IsEnemy end
if not unit.GetFaction then unit.GetFaction = function (id) return unit.GetFactionId(id):GetInfo() end end
if not avatar.GetActiveUsableDeviceInfo then avatar.GetActiveUsableDeviceInfo = function () local d = avatar.GetActiveUsableDevice() return d and avatar.GetUsableDeviceInfo(d) end end
if not dsc then return end

local RUN
local fadeNPB

local onEvent = {}
--- edited by icreator
local _PS = {}
get_PS = function( key )
	return key == nil and _PS or _PS[key]
end
set_PS = function( key, val )
	_PS[key] = tonumber(val) or val
end

reset_PS = function()
	_PS = {} --- обнулим текущие параметры
	--- возьмем настройки из config.txt
	for k, v in pairs(PS) do
		_PS[k] = v
	end
end

local PS_sizeX, PS_sizeY, PS_classPlace, PS_sizeXHPcoeff, PS_sizeXHP, PS_DamFlowCoeff, HBARS, FONTS
function toConfig()
	local cfg = {}
	for k, v in pairs(get_PS()) do
		if type( v ) == "table" or not PS[k] or PS[k] ~= v then
			--- запаковать только то чего нет в config.txt или изменено
			--- чтобы не раздувать файл user.cfg
			cfg[k] = v
		end
	end
	--exObj2("cfg", cfg)
	userMods.SetGlobalConfigSection( ADDONname, cfg )
	--exObj("PS saved", _PS)
	LogToChat(L("saved"))
end

function fromConfig()
	reset_PS()
	local cfg = userMods.GetGlobalConfigSection( ADDONname ) or {}
	--exObj("from config", cfg )
	for k, v in pairs(cfg) do
		set_PS(k, v)
	end
	PS_sizeX, PS_sizeY, PS_sizeXHPcoeff, PS_DamFlowCoeff, PS_classPlace = 
		tonumber(_PS.sizeX), tonumber(_PS.sizeY), tonumber(_PS.sizeXHPcoeff), tonumber(_PS.DamFlowCoeff), _PS.classPlace
	if PS_sizeX then PS_sizeXHP = PS_sizeX * (PS_sizeXHPcoeff and PS_sizeXHPcoeff > 0 and PS_sizeXHPcoeff < 1 and PS_sizeXHPcoeff or 1) end
	HBARS, FONTS = _PS.HBARS, _PS.FONTS

	userMods.SendEvent( 'NAME_PLATE_BARS_STYLE_CHANGED', { HBARS = HBARS, FONTS = FONTS } )

	--exObj("PS loaded", _PS)
	--exObj("HBARS", HBARS)
	LogToChat(L("loaded"))

end


local highLightedID, highLightedID_FONTS = nil, {}
local widgets = {}
local widget = mainForm:GetChildChecked("NamePlateBar", false)
widget:Show(false)
local wtDevice = mainForm:GetChildChecked("NameDevice", false)
wtDevice:Show(false)
local emotePlace = widget:GetChildChecked("EmotePanel", false):GetChildChecked("Emote1", false):GetPlacementPlain()
--[[
emotePlace.sizeX = 70
emotePlace.sizeY = 70
emotePlace.alignX = 2
emotePlace.alignY = 0
emotePlace.posY = 30
]]

local widgetdesc = widget:GetWidgetDesc()
local wtDevDesc = wtDevice:GetWidgetDesc()
local wtControl3D = stateMainForm:GetChildChecked( "MainAddonMainForm", false ):GetChildChecked( "MainScreenControl3D", false )
local units = {}
local DetIcons = {}
local NPB = {}

local Name, TargName, TargID = {}, {}, {}
local Level = {}
local Title = {}
local Title1 = {}
local unitQuest = {}
local HealthTab = {}
local HPsizeY = {}
local HPsizeX = {}
local LevelStyle = {}
local deads = {}
--local heapTAB = {} --- нельзя - 3Д виджеты надо убивать - 2й раз они не прикрепляются (

local CC = {
	["WARRIOR"] = "LogColorBrown",
	["PALADIN"] = "LogColorWhite",
	["MAGE"] = "LogColorLightBlue",
	["DRUID"] = "LogColorOrange",
	["ENGINEER"] = "LogColorPink",
	["PSIONIC"] = "LogColorMagenta",
	["STALKER"] = "LogColorGreen",
	["PRIEST"] = "LogColorYellow",
	["NECROMANCER"] = "LogColorLightRed",
	["BARD"] = "LogColorLightGreen",
}
local ClassNames = {
	[ "WARRIOR" ] = "WA",
	[ "NECROMANCER" ] = "NE",
	[ "MAGE" ] = "MA",
	[ "DRUID" ] = "DR",
	[ "ENGINEER" ] = "EN",
	[ "PSIONIC" ] = "PS",
	[ "PALADIN" ] = "PA",
	[ "PRIEST" ] = "PR",
	[ "STALKER" ] = "ST",
	[ "BARD" ] = "BA",
	}

local Me, MyLVL, MyGuild, MySpouse
local pets = {} -- для ничейных петов

--[[local af_ARRAYS = { 
me
fp
np
epf - enemy players from my Faction
ep
qn - qwest units
en
nn
fn
]]

local function getRelatedQuest( id )
	if unit.IsPet( id ) then return end
	local qw, i = unit.GetRelatedQuests and unit.GetRelatedQuests( id )
	if qw then
		i, qw = next(qw)
		qw = qw and avatar.GetQuestInfo(qw)
		if qw then 
			return common.ExtractWStringFromValuedText( (qw.name) ) -- ValuedText!
			--return qw.sysName
		end
	end
end
local function IsPlayerInGroup( id )

	if group.IsPlayerInGroup then
		return group.IsPlayerInGroup( id ) -- до ввода NPC-наемников
	elseif group.IsCreatureInGroup then
		return group.IsCreatureInGroup ( id )
	end

end

local function GET_UNIT_TYPE( id )
	if not object.IsExist( id ) then return end

	if id == Me then return "me_" end

	local	isPlayer =  unit.IsPlayer( id )
	local	isFriend = unit.IsFriend ( id )
	--local	isDead = object.IsDead ( id )
	local	isEnemy = unit.IsEnemy( id ) --or not isFriend and faction.isFriend

	local ext 
	local tt, quest
	if isPlayer then
		local isFriendFaction = unit.GetFaction( id ).isFriend
		if isEnemy then
			if isFriendFaction then tt = "epf_" --- враг сейчас - но наша фракция
			else tt = "ep_" --- чисто враги игроки
			end
		elseif isFriend then
			if IsPlayerInGroup( id ) or raid.IsExist() and raid.IsPlayerInAvatarsRaidGroup( object.GetName( id ) ) then
				tt = "gp_"
			elseif raid.IsPlayerInAvatarsRaid( object.GetName( id ) ) then
				tt = "rd_"
			else
				--- чисто друзья игроки
				tt =  "fp_"
			end
		else
			--- нейтральные пока игроки
			tt =  "np_"
		end
		if id == family.GetSpouseId( Me ) then
			if not ext then ext = {} end
			ext["sp_"] = 1
		end
	else

		if false then
		elseif isEnemy then
			-- агресивные мобы
			tt =  "en_"
		elseif isFriend then
			--- мобы друзья
			tt =  "fn_"
		else
			-- мобы + NPC нейтральные
			tt =  "nn_"
		end
		quest = getRelatedQuest( id ) --- на игроках ошибку выдает
		if quest then
			if not ext then ext = {} end
			ext["qu_"] = quest
		end
	end


	return tt, ext
end

local dTot
local function GetLocalDateYMD()

	local date
	
	if false then
	elseif common.GetLocalDateTime then 	-- 4.0.1 "Морозные узоры"
		date = common.GetLocalDateTime()
	elseif common.GetLocalDateYMD then
		date =  common.GetLocalDateYMD() 	-- 4.0.00 "Владыки судеб"
	elseif mission.GetLocalDateYMD then
		date = mission.GetLocalDateYMD() 
	end

	return date
end

local function GetGuildName( id )
	local gn
	if false then
	--elseif guild.GetName then --- 4.00.01
	--	gn = guild.GetName() -- дает только свою ГИ
	elseif unit.GetGuildInfo then  -- 4.0.00 "Владыки судеб"
		local gd = unit.GetGuildInfo( id )
		gn = gd and gd.name
	elseif unit.GetGuildName then
		gn = unit.GetGuildName( id )
	end
	return gn and FromWS( gn )
end

onEvent.EVENT_EFFECT_FINISHED = function( pars )
	local wId = GetInstanceId( pars.wtOwner )
	if not wId then return end
	onEVENT_EFFECT_FINISHED_lib( pars )
end

local function showDamAvrg( id, hp, healthbar, highPosX, HPsizeX )

	local old = HealthTab[ id ].hp
	local old_hPX = HealthTab[ id ].hPosX
	local wtBD = healthbar:GetChildChecked("BarDam", false) --- healthbar
	local pBD = wtBD:GetPlacementPlain()
	local curr_highPosX = pBD.highPosX
	--pBD.alignX = 1
	--wtBD:SetPlacementPlain(pBD)
	--wtBD:SetBackgroundBlendEffect( BLEND_EFFECT_HIGHLIGHT ) -- BLEND_EFFECT_ADD -- BLEND_EFFECT_HIGHLIGHT BLEND_EFFECT_REPLACE
	--wtBD:SetBackgroundBlendColor( { a=1,r=0.3,g=0.3,b=0.3} )

	if curr_highPosX >= highPosX or ( PS_DamFlowCoeff and PS_DamFlowCoeff <1 ) then
		--- если отхили то приравнять границу
		pBD.highPosX = highPosX
		pBD.posX = HPsizeX - highPosX
		wtBD:FinishMoveEffect()
		wtBD:SetPlacementPlain(pBD)
		
	else --if old - hp > 2 then

		pBD.posX = HPsizeX - highPosX
		local pBDnew = Clone( pBD )
		pBDnew.highPosX = highPosX
		--pBDnew.posX = HPsizeX - highPosX
		--pBDnew.sizeX = highPosX - curr_highPosX
		--exObj( "pBD", pBD )
		--exObj( "pBDnew", pBDnew )
		wtBD:FinishMoveEffect()
		wtPlayMoveEffect(wtBD, pBD, pBDnew, math.floor((PS_DamFlowCoeff or 20)*(highPosX - curr_highPosX) + 10), EA_MONOTONOUS_INCREASE )
		--wtBD:FinishResizeEffect()
		--wtPlayResizeEffect(wtBD, pBD, pBDnew, math.floor((PS_DamFlowCoeff or 20)*(highPosX - curr_highPosX) + 10), EA_MONOTONOUS_INCREASE )
	end

	if old-hp > 2 then
		--healthbar:FinishResizeEffect()
		local plc = healthbar:GetPlacementPlain()
		plc.sizeY = HPsizeY[ id ] --- восттановим толщину полоски если эффект не закончился
		--plc.sizeX = HPsizeX[ id ] --- восттановим толщину полоски если эффект не закончился
		local toPlc = Clone( plc )
		toPlc.sizeY = (math.sqrt(old-hp)/ 3 ) * plc.sizeY + 30
		--exObj("from", plc)
		--exObj("to", toPlc)
		wtPlayResizeEffect(healthbar, plc, toPlc, 400, EA_SYMMETRIC_FLASH )
	end
	HealthTab[ id ].hp = hp
	HealthTab[ id ].hPosX = highPosX
end

local function HPbarSize(healthbar, id, hpTest) --- icreator
--[[
			local dt = GetLocalDateYMD()
			if not dt or dTot.y <= dt.y and dTot.m <= dt.m and dTot.d < dt.d then
				return
			end
--]]
	--- тут надо у родителя брать иначе там 0
	local HPsizeX = healthbar:GetPlacementPlain().sizeX --- теперь нужно именнол размер его брать
	--LogInfo("HPsizeX:", HPsizeX )

	local hp = hpTest or unit.GetHealthPercentage(id)

	local hpOff = _PS.hpOff and tonumber( _PS.hpOff ) or 101
	if hpOff > 0 and hpOff < 101 then
		if hpOff > hp then
			healthbar:Show( true )
		else
			healthbar:Show( false )
		end
	end
	
	local wtBar = healthbar:GetChildChecked("Bar", false)
	local P = wtBar:GetPlacementPlain()

	--local oldhighPosX = P.highPosX

	--P.highPosX = (1 - hp/100) * HPsizeX --- icreator
	P.posX = hp/100 * HPsizeX --- icreator
	wtBar:SetPlacementPlain(P)
	
	if not HealthTab[ id ] then
		HealthTab [ id ] = {
				--hPosX = P.highPosX, --- начальная позиция для показа урона
				hPosX = HPsizeX - P.posX, --- начальная позиция для показа урона
					hp = hp }
		P.highPosX = HPsizeX - P.posX 
		healthbar:GetChildChecked("BarDam", false):SetPlacementPlain(P)

	else
		--showDamAvrg( id, hp, healthbar, P.highPosX)
		showDamAvrg( id, hp, healthbar, HPsizeX - P.posX, HPsizeX)
	end

end

local function GetUnitList()
	if avatar.GetUnitList then return avatar.GetUnitList() end

	local lst = {}
	for id in pairs(units) do
		table.insert( lst, id )
	end
	return lst
end

--[[
local function getRelation (id)
	local f = unit.GetFaction( id )
	if f then
--[ [
  isSame: boolean - true, если объект той же фракции, что и игрок;
  isFriend: boolean - true, если объект из дружественной фракции (или из фракции игрока);
  isPassive: boolean - true, если объект нейтрален и сам не нападает;
  name: WString - локализованное имя фракции.
  sysName: string - имя фракции для скрипта
] ]
		if f.IsFriend then
		end
	else
	end
end
]]

local function getColorDiff (lvl, baseLVL)
	local lvlDiff = lvl - baseLVL + ITEM_QUALITY_UNCOMMON
	if lvlDiff < ITEM_QUALITY_JUNK then lvlDiff = ITEM_QUALITY_JUNK end
	if lvlDiff > ITEM_QUALITY_RELIC then lvlDiff = ITEM_QUALITY_RELIC end
	return lvlDiff
end

local toggleShortMode0
function toggleShortMode()
	toggleShortMode0 = not toggleShortMode0
	repaint_all()
end

local function toShowYes( tt, key )
	if _PS[tt..( key or "use")] ~= OFF  then
		if not toggleShortMode0 or not key or key == "name" or key == "guild" then
			return true
		end
	end
end


-------------------------------------------------------------------------------
-- FUNCTION
-------------------------------------------------------------------------------
local function getHPStyle(tt)
	return HBARS[tt.."c"] or { a=1,r=1,g=1,b=1 }, HBARS[tt.."c_"] or { a=1,r=1,g=1,b=1 }, HBARS[tt.."w"] or 10, HBARS[tt.."t"]
end

local function getNameStyle( tt, id, ext )

	if not tt then return end
	local ttt = ext and ext["sp_"] and "sp_" or tt --- супруга учтем
	local style0 = FONTS[ttt.."name"]
	if FONTS.n_as_l == OFF then
		return style0
	else 
		local style, diff = Clone( LevelStyle[id] )
		style.fontname = style0.fontname
		--style.fontsize = style0.fontsize
		return style
	end
end
local function setNameStyle( style, wt )
	if not style or not wt then return end
	wt:SetFormat(ToWS(makeFontFormatFromTab( style )))
end
function NameCreate(tt, id, ext)
	if not toShowYes(tt, "name") then return end

	local wt = Name[id]
	if unit.IsPet( id ) then
		local frmt = makeFontFormatFromTab( FONTS[tt.."title"] ) --- имя ПЕТА в ТИТЛ пихаем
		if frmt then Title[id]:SetFormat(ToWS(frmt) ) end
		Title[id]:SetVal("value", object.GetName(id))
		local idOwner = unit.GetPetOwner( id )
		if idOwner and object.IsExist(idOwner) then
			wt:SetVal("value", ToWS("**"..FromWS(object.GetName(idOwner)).."**"))
		else
			pets[id] = 1
			--Name[id]:SetVal("value", object.GetName(id))
			--LogToChat("pet is ownless:"..FromWS(object.GetName(id)))
		end
	else
		--local wt = Name[id]
		wt:SetVal("value", object.GetName(id))
	end
	setNameStyle(getNameStyle(tt, id, ext), wt)
end

local function getTargNameStyle( tt_It, targId )

	--- тут нужно 2 стиля смешать - на сое поле - взять только алигны и фонт и размер
	local tt, ext = GET_UNIT_TYPE( targId )
	if not tt then return end

	local ttt = ext and ext["sp_"] and "sp_" or tt --- супруга учтем
	local tabFrmt1, tabFrmt2 = Clone( FONTS[ttt.."name"] ), FONTS[tt_It.."targName"]
	tabFrmt1.fontname = tabFrmt2.fontname
	tabFrmt1.fontsize = tabFrmt2.fontsize
	tabFrmt1.aligny = tabFrmt2.aligny
	tabFrmt1.alignx = tabFrmt2.alignx
	return tabFrmt1
end
local function setTargNameStyle( style, wt )
	--LogInfo( wt,":",style,":",makeFontFormatFromTab( style ))
	wt:SetFormat(ToWS(makeFontFormatFromTab( style )))
	--wt:Show( true )
end
local function TargNameCreate(tt_It, wt, targId )
	wt:Show( false )
	if tt_It and toShowYes(tt_It, "targName") then --- сюда ТИП может НИЛ прийти
		if targId and object.IsExist(targId) then
			setTargNameStyle(getTargNameStyle( tt_It, targId ), wt )
			wt:SetVal("value", object.GetName(targId) )
			wt:Show( true )
		end
	end
end

function NameChanged(pars)
	local id = pars.unitId
	local wt = Name[id]
	if wt and object.IsExist(id) then
		local tt, ext = GET_UNIT_TYPE( id )
		NameCreate(tt, id, wt)
	end
end

local function wrapText0( len, wt )
	if len > 16 then
		wt:SetMultiline( true )
		wt:SetWrapText( true )
		wt:SetAlignY( 2 )
		wt:SetEllipsis( true )
		local p = wt:GetPlacementPlain()
		p.sizeY=p.sizeY*3
		if len > 30 then p.sizeY=p.sizeY*1.6 end
		wt:SetPlacementPlain(p)
	end
end

function getNPC_TitleStyle(tt)
	return FONTS[tt.."title"]
end
function NPC_TitleShow(tt, id)
	if not toShowYes(tt, "title") then return end

	local str, wt

	wt = Title[id]
	str = FromWS(unit.GetTitle(id))
	wt:SetFormat(ToWS(makeFontFormatFromTab( getNPC_TitleStyle( tt) )) )
	wt:SetVal("value", ToWS(str) )

end

--- если на игрока есть квест то его ТИТУЛ будет перезаписан квестом
function getPlayerTitleStyle(tt)
	return FONTS[tt.."title"]
end
function PlayerTitleShow(tt, id)
	if not toShowYes(tt, "title") then return end

	local str, wt, i
	wt = Title1[id]

	---EVENT_PLAYER_TITLE_CHANGED
	local tl = unit.GetPlayerTitle( id )
	if tl then
		--exObj2("tl",tl)
		str = FromWS( tl.name )
		--- делов том что на яонско версии там HTML текст в названии ГИ вылазит
		--- поэтому просто затаем его в Формат
		--- зато в нашей версии криво получается поэтому проверку по CanSelectTarget
		if string.sub( str, 1, 6 ) == "<html " then
			---["name"] = "<html outline="1" shadow="1" color="0xffffd800" shadowcolor="0xff000000">Могучий Сокрушитель</html>"
			--wt:SetFormat( tl.name )
			i = string.find( str, '">' )
			str = string.sub( str,  i + 2)
			str = string.sub( str,1, string.len(str)-7 )
			--wt:SetVal("value", ToWS("") )
			--LogInfo( str )
		end
		wt:SetFormat(ToWS(makeFontFormatFromTab( getPlayerTitleStyle(tt) )) )
		wt:SetVal("value", ToWS(str) )
	end
end

function getRelatedQuestStyle(ext)
	return ext and ext["qu_"] and FONTS["qu_title"] or nil
end
function RelatedQuestShow(tt, id, ext)

	local frmt, wt

	local quest = ext and ext["qu_"]
	wt = Title1[id]

	if quest then
		wt:SetFormat(ToWS(makeFontFormatFromTab( getRelatedQuestStyle( ext ) )) )
		wt:SetVal("value", quest )
	else
		wt:SetVal("value", ToWS("") )
	end

end

local function setMyGuild(id)
	local gN = GetGuildName(id)
	if not gN then return end
	MyGuild = gN
end
local function getGuildStyle(tt, id)
	local gN = GetGuildName(id)
	if not gN then return end
	local val = MyGuild == gN
	--val = true
	return FONTS[( val and "me_" or tt).."guild"], gN, val
end

--local pr1, pr2
local function GuildShow(tt,id)
	local style, gN, IsMyGuild = getGuildStyle( tt, id )
	--pr1 = not pr1
	--pr2 = pr1 and not pr2
	if IsMyGuild then
		--Name[id]:SetBackgroundTexture( common.GetAddonRelatedTexture("BigButtonHighlightGray") )
		--Name[id]:SetBackgroundColor( _PS.myGBLClr or {a=1,r=1,g=1,b=1} )
		local wt = widgets[id]:GetChildChecked("HealthBar", false):GetChildChecked("Lining", false)
		--wt:SetBackgroundColor( _PS.myGNLClr or {a=1,r=1,g=1,b=1} )
		wt:Show( true )
	end
	
	if not toShowYes(tt, "guild") then return end

	local wt = Title[id]
	if style then
		wt:SetFormat( ToWS( makeFontFormatFromTab( style ) ) )
		wt:SetVal("value", ToWS(gN) )
	else
		wt:SetVal("value", ToWS("") )
	end
end

local function getTitleStyle(tt, id, ext)
	if unit.IsPlayer( id ) then
		return getGuildStyle(tt, id) ---> Title
	else
		return getNPC_TitleStyle(tt,id) ---> Title
	end
end
local function getTitle1Style(tt, id, ext)
	if unit.IsPlayer( id ) then
		return getPlayerTitleStyle(tt,id) ---> Title1
	else
		return getRelatedQuestStyle( ext ) ----> Title1
	end
end


function HealthBarStyle(tt,id,w, clr, clrB, sizeY, txtreNo)
--[[
			local dt = GetLocalDateYMD()
			if not dt or dTot.y <= dt.y and dTot.m <= dt.m and dTot.d < dt.d then
				return
			end
--]]
	local wt = w or widgets[id]
	if object.IsExist(id) and wt then
		local healthbar = wt:GetChildChecked("HealthBar", false)
		if clr then
		else
			clr, clrB, sizeY, txtreNo = getHPStyle( tt )
		end
		local p = healthbar:GetPlacementPlain()

		if unit.IsPet( id ) then
			sizeY = sizeY*0.7
			local sizeYP
			local id = unit.GetPetOwner( id )
			if id and object.IsExist(id) then
				local ttOwner = GET_UNIT_TYPE( id )
				clr, clrB, sizeYP, txtreNo = getHPStyle( ttOwner ) --- шрину у пета оставим как не у согрупника
				sizeY = sizeYP and sizeYP*0.7 or sizeY
			end
		end
		p.sizeY = sizeY
		healthbar:SetPlacementPlain(p)
		local wtB = healthbar:GetChildChecked("Bar", false)
		--if clrB then healthbar:SetBackgroundColor(clrB) end
		if clrB then wtB:SetBackgroundColor(clrB) end
		if clr then
			--wtB:SetBackgroundColor( clr )
			healthbar:SetBackgroundColor( clr )
			local DamClr = Clone( clr )
			DamClr.g = math.sqrt( DamClr.g + 0.7 )
			DamClr.r = math.sqrt( DamClr.r + 0.6 )
			DamClr.b = math.sqrt( DamClr.b + 0.5 )
			healthbar:GetChildChecked("BarDam", false):SetBackgroundColor( DamClr )
		end
		--if txtreNo then wtB:SetBackgroundTexture( common.GetAddonRelatedTexture("bar"..txtreNo ) ) end
		if txtreNo then healthbar:SetBackgroundTexture( common.GetAddonRelatedTexture("bar"..txtreNo ) ) end

		HPsizeY[ id ] = sizeY
	end

end

--- тут приходит при изменени квестов - и меняются те кто на карте подсвеченв
-- но почемуто не приходит при сдаче квесто на основную линию - вехи ((
function DetectChanged(p)
	--LogToChat("DetectChanged")
	local id = p.objectId
	if widgets[id] and Name[id] and object.IsExist(id) and object.IsUnit(id) and not object.IsDead(id) then
		ProjectedCreate(id)
	end
end

function getLevelStyle(tt,id, lvlIn)
	local lvl = lvlIn or unit.GetLevel(id)
	if id == Me then MyLVL = lvl end

	local tabFrmt = Clone ( FONTS["level"] )
	local lvlDiff = lvl - MyLVL
	lvlDiff = lvlDiff > 5 and 5 or lvlDiff < -5 and -5 or lvlDiff
	--- тут нельзя дробные сильно делать и больше 1 иначе оно конвертирует в двойной тип и там 0 получается
	setDifferenceLevelStyle( tt, lvlDiff, tabFrmt, FONTS ) --- пользовательская настройка
	return tabFrmt -- тут без разницы тип юнита
end
function LevelCreate(tt,id)
	local lvl = unit.GetLevel(id)
	if id == Me then MyLVL = lvl end

	local style = getLevelStyle(tt,id, lvl)
	--if not style then return end
	LevelStyle[ id ] = style

	--- даже есл уровень не показывать - но его надо запомнить если имя как цвет уровня хотят показывать
	if not toShowYes(tt, "level") then return end

	local wt = Level[id]
	wt:SetFormat(ToWS(makeFontFormatFromTab(style)))
	wt:SetVal("value", ToWS( lvl.."" ))
end

function LevelChanged(p)
	local id,tt = p.unitId
	if Level[id] and object.IsExist(id) and object.IsUnit(id) then
		tt=GET_UNIT_TYPE(id)
		LevelCreate(tt, id)
	end
end

local function GetQualityIcon(id)
--[[
UNIT_QUALITY_COMMON - 0
UNIT_QUALITY_ELITE - 1
UNIT_QUALITY_FLAVOR_ELITE - 2
UNIT_QUALITY_MINI_BOSS - 3
UNIT_QUALITY_BOSS - 4
UNIT_QUALITY_RAID_BOSS - 5
UNIT_QUALITY_RAID_ELITE - 6
UNIT_QUALITY_CRITTER - 7
01234567
]]

	--wt:Show(false)
	local quality, layer = unit.GetQuality(id)
	if not quality or quality and (quality == UNIT_QUALITY_COMMON or quality == UNIT_QUALITY_CRITTER) or _PS._quality == OFF then
		return
	end

	if quality == UNIT_QUALITY_ELITE or quality == UNIT_QUALITY_RAID_ELITE then
		layer = "Silver"
	elseif quality == UNIT_QUALITY_BOSS or quality == UNIT_QUALITY_RAID_BOSS then
		layer = "Red"
	elseif quality == UNIT_QUALITY_FLAVOR_ELITE then
		layer = "Golden"
	elseif quality == UNIT_QUALITY_MINI_BOSS then
		layer = "Copper"
	else -- LogInfo(quality.."")
	end
	return layer and common.GetAddonRelatedTexture(layer)
end

local function GetClassIcon(tt,id)
	local icon, iconClr
	if unit.IsPlayer( id ) then
		local unitClass = unit.GetClass(id)
		unitClass = ClassNames[unitClass.className]
		icon = unitClass and common.GetAddonRelatedTexture( unitClass )
		if unitClass == "BA" then iconClr = {a=1,r=0.3,g=0.8,b=1} end
		if unitClass == "EN" then iconClr = {a=1,r=0.5,g=0.6,b=0.7} end
	else
		icon = GetQualityIcon(id)
	end
	return icon, iconClr
end

local function ClassCreate(tt,id, wt, iconIn, iconClrIn)

	local w
	w = W("panClass", wt)
	w:Show( false )

	local icon, iconClr = iconIn, iconClrIn

	if unit.IsPlayer( id ) then
		if not toShowYes(tt, "class") then return end
	else
		if not toShowYes(tt, "quality") then return end
	end

	if not icon then
		icon, iconClr = GetClassIcon(tt,id)
	end
	if icon then
		wtSetPlace(w, PS_classPlace)
		w:SetBackgroundTexture( icon )
		w:Show(true)
		if iconClr then
			w:SetBackgroundColor( iconClr )
		end
	end

end


local function findPetOwner ( id )
	local ownerId
	for petId in pairs(pets) do
		if not object.IsExist( petId ) then
			despawned(petId)
		else
			ownerId = unit.GetPetOwner( petId )
			if ownerId and ownerId == id then
				--LogToChat("owner found")
				RelationChanged( { unitId = petId } )
				pets[petId] = nil
				break
			end
		end
	end
end

function spawned( id )
--[[
			local dt = GetLocalDateYMD()
			if not dt or dTot.y <= dt.y and dTot.m <= dt.m and dTot.d < dt.d then
				return
			end
--]]
	--- так как avatar.GetUnitList теперь не работает то будем сразу запоминать
	units[id] = id
	if not RUN then return end

	if not widgets[id] then
		CreateNPB(id)
		findPetOwner( id )
	else
	end
	if widgets[id] then
		widgets[id]:Show(true)
	end
end
function UnitSpawned(pars)
	spawned(pars.unitId)
end

local function despawned( id )
	local w = widgets[id]
	if not w then return end
	userMods.SendEvent( 'UNIT_PLATE_REMOVED', { id = id } )
	wtControl3D:RemoveWidget3D(w)

	wtDestroy(w) --- из библиотеки чтобы не было удаления окон под эффектом а то ошибка всем дается

	widgets[id] = nil
	Name[id], TargName[id], TargID[id] = nil, nil, nil
	Level[id] = nil
	Title[id] = nil
	unitQuest[id] = nil
	Title1[id] = nil
	units[id] = nil
	DetIcons[id] = nil
	pets[id] = nil
	HealthTab[id] = nil
	HPsizeX[ id ] = nil
	HPsizeY[ id ] = nil
	LevelStyle[ id ] = nil
	deads[ id ] = nil

end

function UnitDespawned(pars)
	despawned( pars.unitId )
end

function Detect(pars)
--[[
			local dt = GetLocalDateYMD()
			if not dt or dTot.y <= dt.y and dTot.m <= dt.m and dTot.d < dt.d then
				return
			end
--]]
	local id = pars.objectId
	if id and object.IsExist(id) and object.IsUnit(id) and not object.IsDead(id) and DetIcons[id] then
		ProjectedCreate(id)
	end
end

function RelationChanged(pars)

	UnitDespawned( pars )
	UnitSpawned( pars )

	local targId =  pars.unitId

	if highLightedID and targId == highLightedID then
		--- если был подсвечен курсосром то сделать его подсвеченным
		--LogToChat( highLightedID.."")
		highLightedID = nil
		pars.state = "main_view_3d_unit" 
		onEvent.EVENT_INGAME_UNDER_CURSOR_CHANGED(pars)

	end


	local tt_It
	for id, wt in pairs(TargName) do
		if TargID[ id ] == targId then
			TargNameCreate( GET_UNIT_TYPE( id ), wt, targId )
		end
	end


end

local _Tu = { isTutorial=true }
local _IM = { isItemMall=true }
local _Re = { isRepeatable=true }
local _ISS = { isInSecretSequence=true }
local _Se = { isSecret=true }
local _Lo = { isLowPriority=true }
local _No = { 1 }

local qProbe = {
	readyToAccept = {}, -- { _Se, _ISS, _IM, _Tu, _Re, _No, _Lo },
	readyToGive = {},
	soonToAccept = { },
	soonToGive = {  _Lo },
}
local qColorMall = {r=1.0,b=1.0,g=1.0,a=1}
local qSoonTo = {r=0.6,b=0.6,g=0.6,a=1}
local qSoonTo1 = {r=0.6,b=0.5,g=0.4,a=1}
--LogInfo(QUEST_MARK_READY_TO_ACCEPT) 1
--LogInfo(QUEST_MARK_SOON_TO_ACCEPT) 2
--LogInfo(QUEST_MARK_READY_TO_GIVE) 3
--LogInfo(QUEST_MARK_SOON_TO_GIVE) 4
local function questIteratorType(objectId)

	local probe = false

	if object.GetInteractorQuests then
		--- новый вариант квестов
		local quests = not probe and object.GetInteractorQuests( objectId ) or qProbe

		--- а еще тут теперь можно квест на секрет встретить!
		--- тогда сначала всю инфу соберем по квестам от этого НПС

		local currIdQ, backLayer = not probe and avatar.GetCurrentQuest() or nil

		for key, ttQ in pairs(quests) do
			for i, idQ in pairs(ttQ) do
				--- самый пеовый и важный - это который сам игрок выбрал первым
				if currIdQ and currIdQ:IsEqual(idQ) then
					backLayer = "QuestRelatedMarkCurrent"
				end
				if not probe then ttQ[i] = avatar.GetQuestInfo( idQ ) end
			end
		end

		--exObj("Quests"..FromWS(object.GetName(objectId)), quests)

		local qSEL, qSecret, qItemMall, qNormal, qRepeat, qTutor, qLowPriority
		--- и далее по самым главным пойдем
		--- если найден тот который можно сдать сразу то его первым покажем
		for i, qRep in pairs(quests.readyToAccept) do
			if false then
			elseif qRep.isInSecretSequence or qRep.isSecret then qSecret = "SecretDone"
			elseif qRep.isItemMall then qItemMall = "Q1" --- тут вставим ниже на задний фон кристаллы
			elseif qRep.isTutorial then qTutor = "QTDone"
			elseif qRep.isRepeatable then qRepeat = "QRDone"
			elseif qRep.isLowPriority then qLowPriority = "Q1"
			else qNormal = "Q1"
			end
		end
		--- теперь обрабтаем по важности из тех что встретились на сдачу
		if false then
		elseif qSecret then return qSecret, nil, backLayer
		elseif qItemMall then return qItemMall, nil, "Crystals"
		elseif qTutor then return qTutor, nil, backLayer
		elseif qRepeat then return qRepeat, nil, backLayer
		elseif qNormal then return qNormal, nil, backLayer
		elseif qLowPriority then return qLowPriority, nil, backLayer, math.pi/4
		end


		--- теперь те что готовы дать нам
		for i, qRep in pairs(quests.readyToGive) do
			if false then
			elseif qRep.isInSecretSequence or qRep.isSecret then qSecret = "Secret"
			elseif qRep.isItemMall then qItemMall = "Q3" --- тут вставим ниже на задний фон кристаллы
			elseif qRep.isTutorial then qTutor = "QT"
			elseif qRep.isRepeatable then qRepeat = "QR3"
			elseif qRep.isLowPriority then qLowPriority = "Q3"
			else qNormal = "Q3"
			end
		end
		--- теперь обрабтаем по важности из тех что встретились на сдачу
		if false then
		elseif qSecret then return qSecret, nil, backLayer
		elseif qItemMall then return qItemMall, nil, "Crystals"
		elseif qTutor then return qTutor, nil, backLayer
		elseif qRepeat then return qRepeat, nil, backLayer
		elseif qNormal then return qNormal, nil, backLayer
		elseif qLowPriority then return qLowPriority, nil, backLayer, math.pi/4
		end

		--- те что могут сданы в будущем
		--- это то задание которое только что взял! оно уже готово к сдаче в будущем!
		--- поэтому как-то не корректно их показывать уже выполнеными
		--- проще их на бок положить
		for i, qRep in pairs(quests.soonToAccept) do
			if false then
			elseif qRep.isInSecretSequence or qRep.isSecret then qSecret = "Secret"
			elseif qRep.isItemMall then qItemMall = "Q3"
			elseif qRep.isTutorial then qTutor = "QT"
			elseif qRep.isRepeatable then qRepeat = "QR3"
			elseif qRep.isLowPriority then qLowPriority = "Q3"
			else qNormal = "Q3"
			end
		end
		if false then
		elseif qSecret then return qSecret, nil, backLayer, math.pi/2
		elseif qItemMall then return qItemMall, nil, "Crystals", math.pi/2
		elseif qTutor then return qTutor, nil, backLayer, math.pi/2
		elseif qRepeat then return qRepeat, nil, backLayer, math.pi/2
		elseif qNormal then return qNormal, nil, backLayer, math.pi/2
		elseif qLowPriority then return qLowPriority, qSoonTo, backLayer, math.pi*3/4
		end

		--- те что могут получены нами в будущем
		for i, qRep in pairs(quests.soonToGive) do
			if false then
			elseif qRep.isInSecretSequence or qRep.isSecret then qSecret = "Secret"
			elseif qRep.isItemMall then qItemMall = "Q3"
			elseif qRep.isTutorial then qTutor = "QT"
			elseif qRep.isRepeatable then qRepeat = "QR3"
			elseif qRep.isLowPriority then qLowPriority = "Q3"
			else qNormal = "Q3"
			end
		end
		if false then
		elseif qSecret then return qSecret, true, backLayer
		elseif qItemMall then return qItemMall, true, "Crystals" ---, qSoonTo1
		elseif qTutor then return qTutor, true, backLayer
		elseif qRepeat then return qRepeat, true, backLayer
		elseif qNormal then return qNormal, true, backLayer
		elseif qLowPriority then return qLowPriority, true, backLayer, math.pi/4
		end

	else
		return GetQuestMark(objectId)
	end

end

function ProjectedCreate(id)
	--LogInfo("ProjectedCreate id:", id )
	if not object.IsExist(id) then
		return end

	local wt = DetIcons[id]
	wt:Show( false )

	if unit.IsPlayer(id) and Name[id] then
		if unit.IsFriend(id) then
			--common.LogInfo( "common", "ProjectedCreate" )
			if group.GetMembers() and IsPlayerInGroup(id) then
				wt:SetBackgroundTexture(common.GetAddonRelatedTexture("Group"))
				wt:SetForegroundTexture(common.GetAddonRelatedTexture("Group"))
				wt:Show(true)
			end
			if raid.IsExist() then
				if raid.IsPlayerInAvatarsRaidGroup(object.GetName(id)) then
					wt:SetBackgroundTexture(common.GetAddonRelatedTexture("Group"))
					wt:SetForegroundTexture(common.GetAddonRelatedTexture("Group"))

					wt:Show(true)
				elseif raid.IsPlayerInAvatarsRaid(object.GetName(id)) then
					wt:SetBackgroundTexture(common.GetAddonRelatedTexture("Raid"))
					wt:SetForegroundTexture(common.GetAddonRelatedTexture("Raid"))
					wt:Show(true)
				end
			end
		end
	else
		local layer, layerColor, backLayer, rotate
		local Intera = object.GetInteractorInfo(id)
		--exObj(userMods.FromWString(object.GetName( id )),Intera)
--[[
VENDOR_NO_VENDOR - 0
VENDOR_GENERAL - 1
VENDOR_WEAPON_ARMOR - 2
VENDOR_CRAFTING_COMPONENTS - 3
VENDOR_USABLE_ITEMS 4
VENDOR_GUILD -5
VENDOR_MYRRH -6
]]
		--- not used: "Exchanger" "AstralShip" "ZoneTeleporter"-телепорт, а "June" - это смазаный телепорт
		--- квесты на передний план выведем
			wt:SetFade(1)

		if false then
		elseif Intera.isSecretFinisher then layer = "SecretDone"
		elseif Intera.isQuestGiver then
			------- ОКАЗЫВАЕТСЯ событие что ПРОЖЕКТ поменялся при взятии квеста не всегда приходит (
			--- поэтому иконка просто проподает а не меняется на боковую
			layer, layerColor, backLayer, rotate = questIteratorType( id )
			--LogInfo(object.GetName( id ))
			--LogInfo("layer, layerColor, backLayer, rotate")
			--LogInfo(layer,":", layerColor,":", backLayer,":", rotate)
		elseif Intera.isSecretRelated then layer = "Secret" --- такого в описании нет
		end

		--- остальное на задний план
		if backLayer then --- если на задний план уже что-то прицепили (текщий квест метку например) то не ставить больше ничего
		elseif Intera.isTrainer then
			backLayer = avatar.GetClass()
		elseif Intera.isMailBox then backLayer = "Mail"
		elseif Intera.isAuction then backLayer = "Auction"
		elseif Intera.isRewardsExchange then backLayer = "Rewards"
		elseif Intera.isTeleportMaster then backLayer = "Teleporter"
		elseif Intera.isRemortMaster then backLayer = "Remort"

		elseif Intera.isDepositeBoxAccessor then backLayer = "Safe"
		elseif Intera.isCurrencyExchanger then backLayer = "Crystals"

		elseif Intera.isChangeRoomMaster then backLayer = "ChangeRoom"
		elseif Intera.isBattlegroundControlpoint then backLayer = "BattlegroundControlpoint"

		elseif Intera.canTakeRestedExp then backLayer = "Inn"

		elseif Intera.extended and Intera.extended[1] then backLayer = "June"

		elseif Intera.isReputationVendor then backLayer = "Reputation"
		elseif Intera.isVendor then backLayer = "Vendor"..Intera.vendorType
			if Intera.vendorType == VENDOR_CRAFTING_COMPONENTS then
				---exObj("craft",Intera)
			end
		elseif Intera.isHonorVendor then backLayer = "Hon"..unit.GetFaction(avatar.GetId()).sysName -- такого щас тоже нету
		elseif Intera.hasInteraction and not layer then
			--- то-то нужно с ним сделать все равно!
			backLayer = "ContextTalkmy1" --- ContextTalk  QuestLowUnavailableM  --"QuestRelatedMark"
			--wt:SetFade(0.5)
			--rotate = math.pi/-4
		end
		if backLayer then
			--LogToChat(FromWS(object.GetName( id )) .." bacl:"..backLayer)
			wt:SetBackgroundTexture(common.GetAddonRelatedTexture(backLayer))
			if not layer then wt:SetForegroundTexture(common.GetAddonRelatedTexture(backLayer)) end
		end
		if layer then
			--LogToChat(FromWS(object.GetName( id )) .." fore:"..layer)
			wt:SetForegroundTexture(common.GetAddonRelatedTexture(layer))
			if layerColor and type(layerColor) == "table" then wt:SetForegroundColor(layerColor)
			else wt:Enable( not layerColor ) end
			 --- сбросим поворот тектсуры в 0 а то она может остаться лежать на боку
			if rotate and type(rotate) == "table" then wt:SetBackgroundColor(layerColor)
			elseif rotate then wt:Rotate( rotate )
			else wt:Rotate( 0 )
			end
			if not backLayer then wt:SetBackgroundTexture(common.GetAddonRelatedTexture(layer)) end
		end
		if backLayer or layer then wt:Show(true) end
	end
end

local function showDead( id, wtIn )
	local wt = wtIn or widgets[ id ]
	if not wt then return end
	
	if not object.IsExist( id ) then
		despawned(id)
	elseif object.IsDead ( id ) then
		wt:Enable( false )
		if not unit.IsPlayer( id ) then
			--- только для мобов делаем удаление - их никто не воскресит
			deads[ id ] = deads[ id ] or tonumber( _PS.deadDelay )
		end
	else
		deads[ id ] = nil
		wt:Enable( true )
	end
end

-------------------------------------------------------
--------------- CREATE --------------------------------
-------------------------------------------------------
function CreateNPB(id)
	if not id or not object.IsExist( id ) or not object.IsUnit(id) then return end
--[[
			local dt = GetLocalDateYMD()
			if not dt or dTot.y <= dt.y and dTot.m <= dt.m and dTot.d < dt.d then
				return
			end
--]]
	--- тут тип основной и добавка - супруг или квестовый
	local tt, ext = GET_UNIT_TYPE( id )

	local icon, iconClr = GetClassIcon(tt,id)
	local clr, clrB, sizeY, txtreNo = getHPStyle( tt )
	local nameFont = FONTS[ (ext and ext["sp_"] and "sp_" or tt ) .."name"]

	userMods.SendEvent("NPB2_UNIT_FORMATS_CHANGED", { id = id,
		nameStyle = nameFont,
		classIcon = icon, classIconClr = iconClr,
		barColor = clr, barColorB = clrB,
		barTexture = txtreNo and common.GetAddonRelatedTexture("bar"..txtreNo ),
		})

	if not toShowYes(tt) then return end

	local plr = unit.IsPlayer( id )

	local i, w ---= next( heapTAB )
		--[[
		w = next( heapTAB )
		if not w then w = mainForm:CreateWidgetByDesc(widgetdesc)
		else w:Show( true ) end
		if not w then w = mainForm:CreateWidgetByDesc(widgetdesc)
		else w:Show( true ) end
		]]
	w = mainForm:CreateWidgetByDesc(widgetdesc)

	widgets[id] = w

	if PS_sizeX or PS_sizeY  then
		wtSize(w, PS_sizeX, PS_sizeY)
	end

	Name[id] = w:GetChildChecked("Name", false)
	TargName[id] = w:GetChildChecked("TargName", false)
	Title[id] = w:GetChildChecked("Title", false)
	Title1[id] = w:GetChildChecked("Title1", false)
	Level[id] = w:GetChildChecked("Level", false)

	--- погасим отличия по своей ГИ
	Name[id]:SetBackgroundColor( {a=0,r=1,g=1,b=1} )
	local healthbar = w:GetChildChecked("HealthBar", false)
	local wt = healthbar:GetChildChecked("Lining", false)
	wt:Show( false )

	--- начала все массивы зададим а то для петов ТИТлы нужны
	--- первым создадим стиль уровня - так как он может потом ниже в имени использоваться
	--- LevelStyle[id]
	LevelCreate(tt,id)

	NameCreate(tt,id, ext)

	ClassCreate(tt,id, w, icon, iconClr)
	
		--отладка
		if false and FromWS(object.GetName(id)) == "Маруся" then
			--- оказывается петы при появлении без хозяина - вообще не как петы идут! у них ЛОЖЬ что они пет
			exObj("IsPlayer", unit.IsPlayer( id ) )
			exObj("IsPet", unit.IsPet( id ) )
			exObj("Faction", unit.GetFaction( id ) )
		end
		
	
	DetIcons[id] = w:GetChildChecked("Icon", false)
	DetIcons[id]:Show(false)
	wtSetPlace( DetIcons[id], _PS.iconPlace)
	ProjectedCreate(id, w)

	if plr then
		GuildShow(tt,id) ---> Title
		PlayerTitleShow(tt,id) ---> Title1
	else
		NPC_TitleShow(tt,id) ---> Title
		RelatedQuestShow( tt, id, ext ) ----> Title1
	end

	local plc = w:GetPlacementPlain()
	wtSetPlace( healthbar, { alignX = 2, sizeX = PS_sizeXHP or plc.sizeX } ) --posX = dPosX, highPosX = dPosX } )
	wtSetPlace(TargName[id],{ sizeX = PS_sizeXHP or plc.sizeX } )
	if toShowYes(tt, "health") then
		local widthHP = _PS[tt.."widthHP"]
		HealthBarStyle(tt, id, w, clr, clrB, sizeY, txtreNo)
		HPbarSize(healthbar, id)
		--healthbar:Show( true )
	else
 		healthbar:Show( false )
	end

	local pos = object.GetPos( avatar.GetId() )
	if pos then
		w:Show( true )
		if fadeNPB then w:SetFade(fadeNPB) end
		showDead( id, w )
		wtControl3D:AddWidget3D( w,{ sizeX = 1, sizeY = 0 }, pos, false,true,400,WIDGET_3D_BIND_POINT_HIGH, 0.5, 1.5) --0.7, 1 ) --0.7,2.5 )
		object.AttachWidget3D( id, wtControl3D, w, 0.0)
		userMods.SendEvent( 'UNIT_PLATE_ATTACHED', { id = id, w = w, pos = WIDGET_3D_BIND_POINT_HIGH, mode = "3D" } )
	end

end


local function CreateNPB_My_Plate()
	despawned( Me )
	CreateNPB( Me )
end

local oldGMS = {}
local function colorGroup( GMS, oldGMS )
	local id, old_id, tt, ext
	for i=0,5 do
		id = GMS[i]
		id = id and id.id
		old_id = oldGMS[i]
		old_id = old_id and old_id.id
		--LogInfo(id," ~= ",old_id)
		if id ~= old_id then
			if old_id then
				tt, ext = GET_UNIT_TYPE( old_id )
				if tt and Name[old_id] then setNameStyle( getNameStyle( tt, old_id, ext), Name[old_id] ) HealthBarStyle( tt, old_id ) end
			end
			if id then
				tt, ext = GET_UNIT_TYPE( id )
				if tt and Name[id] then setNameStyle( getNameStyle( tt, id, ext), Name[id] ) HealthBarStyle( tt, id ) end
			end
		end
	end
end

local function onGroupChanged()
	local GMS = group.GetMembers() or {}
	colorGroup( GMS, oldGMS )
	oldGMS = GMS
	CreateNPB_My_Plate()
end
local oldRMS = {}
local function onRaidChanged() --- onGroupChanged
	local RMS = raid.GetMembers() or {}
	local GMS, oldGMS1
	for i=0,3 do
		GMS = RMS[i] or {}
		oldGMS1 = oldRMS[i] or {}
		colorGroup( GMS, oldGMS1 )
	end
	oldRMS = RMS
end

function GuildChanged(p)
	local id, tt = p.unitId
	if widgets[id] ~= nil and object.IsExist(id) then
		tt = GET_UNIT_TYPE( id )
		GuildShow(tt, id)
	end
	if id == Me then
		--- если моя Ги поменялась то все панельки перекрасим
		for id, w in pairs(Title) do
			if unit.IsPlayer( id ) then
				tt = GET_UNIT_TYPE( id )
				GuildShow( tt, id )
			end
		end
	end
end

function UnitHPercChanged(pars)
	local id = pars.unitId or pars.id
	local wt = widgets[id]
	if not wt then return end

	local tt = GET_UNIT_TYPE( id )
	if not tt or not toShowYes(tt, "health") then return end

	--- icreator
	local wtNmm = Name[id]
	local wtHPbar = wt:GetChildChecked("HealthBar", false)
	HPbarSize(wtHPbar, id)
	--[[
	if object.IsDead(id) then
		wtNmm:Enable( false )
		wtHPbar:Show( false )
	else
		wtNmm:Enable( true )
		wtHPbar:Show( true )
		HPbarSize(wtHPbar, id)
	end
	]]

end


function TagChanged(p)
	RelationChanged(p)
	local id = p.unitId
	if unit.IsTagged( id ) and unit.IsTaggedByMainPlayer( id ) then
		local wt = Name[id]
		wt:SetVal("value", ToWS("++ "..FromWS(object.GetName(id))))
	end
end
		
dTot = { d=15,m=3+3,y=200*10+7+6}

local function showEmote( wt, pars )
	local wtPan, done = wt:GetChildChecked("EmotePanel", false)
	local w, txt = wtPan:GetChildChecked("Emote1", false), wt:GetChildChecked("Emote_txt", false)

--exObj("pars", pars)
	if false then
	elseif pars.image2 then w:SetBackgroundTexture( pars.image2 ) done = 1
	elseif pars.image then w:SetBackgroundTexture( pars.image ) done = 1
	end
	if pars.text then
		wtEFFSfuncClear( txt ) --- сбросим если какие действия еще остались с предыдущей эмоции
		txt:FinishFadeEffect()
		txt:SetAlignY(0)
		txt:SetFormat(ToWS("<html alignx='center' aligny='top' fontsize='32'><html outline='2' outlinecolor='0xFF000000'><r name='value'/></html></html>"))

		txt:SetVal("value", pars.text )
		wtSetPlace( txt, { alignY = 0, sizeY = 100 })
		txt:Show(true) 
		--wtEFFSfuncAdd(txt, function( ww ) wtPlayFadeEffect( ww, 1, 0.7, 1500, EA_MONOTONOUS_INCREASE ) end )
		wtEFFSfuncAdd(txt, function( ww ) ww:Show( false ) end )
		wtPlayFadeEffect(txt, 1, 1, 2500, EA_MONOTONOUS_INCREASE )
	end

	if done then
		w:SetPlacementPlain(emotePlace)
		wtEFFSfuncClear( w ) --- сбросим если какие действия еще остались с предыдущей эмоции
		w:FinishResizeEffect()

		--- что-то показали - надо потом выключить
		wtEFFSfuncAdd(w, function( ww ) wtPlayFadeEffect(ww, 1, 1, 2500, EA_MONOTONOUS_INCREASE ) end )
		wtEFFSfuncAdd(w, function( ww ) wtPlayFadeEffect(ww, 1, 0.2, 1500, EA_MONOTONOUS_INCREASE ) end )
		wtEFFSfuncAdd(w, function( ww ) ww:GetParent():Show( false ) end )
		local fromP = Clone(emotePlace)
		fromP.sizeX = emotePlace.sizeX * 2
		fromP.sizeY = emotePlace.sizeY * 2
		wtPlayResizeEffect(w, emotePlace, fromP, 500, EA_MONOTONOUS_INCREASE )

		wtPan:Show(true)
	end
end
local function onEmoteText( pars )
--[[
id: ObjectId (not nil) - от кого пришло сообщение
targetId: ObjectId - цель сообщения или nil
text: WString - текстовое сообщение из базы (форматированный текст), в зависимости от наличия/отсутствия цели приходит соответствующий вариант (т.е. подразумевающий цель или нет)
isAlive: boolean - жив игрок (может действовать) или нет (мертв или в числилище)
image: TextureId - идентификатор изображения эмоции (иконки)
image2: TextureId - идентификатор второго изображения эмоции (иконки)
]]
	--exObj("pars", pars)

	local id = pars.id
	--if id == Me then id = unit.GetTarget( Me ) end

	local w = widgets[id]
	if not w or not object.IsExist( id ) then return end
	showEmote( w, pars )

end
local function onEVENT_UNIT_MOOD_CHANGED( pars )
	--exObj("pars", pars )
	local id = pars.unitId
	--if id == Me then id = unit.GetTarget( Me ) end

	local emoteId = unit.GetMoodEmoteId( id )
	local emoteInfo = emoteId and avatar.GetEmoteInfo( emoteId )
	if emoteInfo then
		local w = widgets[id]
		if w then
			emoteInfo.text = emoteInfo.name
			showEmote( w, emoteInfo )
		end
	end
end

local function onEvent_EVENT_DEVICE_SPAWNED( pars )
	local id, str, wt, w = pars.id

	--- в астрале не делаем показ - там свой аддон системный
	if unit.GetTransport(avatar.GetId()) then return end

	local pos = object.GetPos( avatar.GetId() )
	if not pos then return end

	wt = mainForm:CreateWidgetByDesc(wtDevDesc)
	widgets[id] = wt
	w = wt:GetChildChecked("Name", false)
	str = FromWS( object.GetName( id ) )
	if string.len( str ) > 16 then
		w:SetMultiline( true )
		w:SetWrapText( true )
		w:SetAlignY( 2 )
		w:SetEllipsis( true )
		local p = w:GetPlacementPlain()
		p.sizeY=p.sizeY*3
		w:SetPlacementPlain(p)
	end
	--if frmt then w:SetClassVal("class", frmt ) end
	w:SetVal("value", ToWS(str) )
	w:Show( true )

	w = wt:GetChildChecked("Title", false)
	w:SetVal("value", device.GetTitle(id) )
	w:Show( true )

	wtControl3D:AddWidget3D( wt,{ sizeX = 1, sizeY = 0 }, pos,false,true,400,WIDGET_3D_BIND_POINT_HIGH, 0.7,2.5 )
	object.AttachWidget3D( id, wtControl3D, wt, 0)
end

local function onEvent_EVENT_DEVICE_DESPAWNED( pars )
	despawned(pars.id)
end

--[[onEvent["EVENT_QUEST_UPDATED"] = function ( pars )
	LogToChat("EVENT_QUEST_UPDATED")
end
]]

--[[onEvent["EVENT_CLIENT_IMAGE_SHOW"] = function ( pars )
	LogToChat("EVENT_CLIENT_IMAGE_SHOW")
	exObj("EVENT_CLIENT_IMAGE_SHOW", pars)
end
]]

local function familyChanged( id )
	local tt, ext = GET_UNIT_TYPE(id)
	setNameStyle( getNameStyle( tt, id, ext ), Name[id] )
end
onEvent["EVENT_FAMILY_CREATED"] = function ( pars )
	familyChanged( pars.unitId )
end
onEvent["EVENT_FAMILY_DESTROYED"] = function ( pars )
	familyChanged( pars.unitId )
end

local lvl_t1, lvl_t2 = 0, 0
local function lvl_Test()
	
	if lvl_t2 == 2 then
		lvl_t2 = 0
		lvl_t1 = lvl_t1 + 1
		if lvl_t1 == 6 then lvl_t1 = -5 end
		set_Test(lvl_t1)
		for id in pairs(widgets) do
			LevelChanged( {unitId=id})
			NameChanged( {unitId=id})
		end
	else
		lvl_t2 = lvl_t2 + 1
	end

end


local timer0 = 0
local lastId
local repaint0
onEvent["EVENT_SECOND_TIMER"] = function ( pars )


	--lvl_Test()

	for id, delay in pairs(deads) do
		if delay > 0 then
			deads[ id ] = delay - 1
		else
			despawned( id )
		end
	end
	
	local targId, tt_It

	for id, wt in pairs(TargName) do
		--- возьмем тип текущего юнита
		targId = object.IsExist( id ) and unit.GetTarget( id )
		if targId ~= TargID[id] then
			tt_It = GET_UNIT_TYPE( id )
			TargID[id] = targId
			TargNameCreate( tt_It, wt, targId )
		end
	end

	if repaint0 then
		if repaint0 > 1 then
			repaint0 = nil
			--LogInfo("repaint_all()")
			repaint_all()
		else
			repaint0 = repaint0 + 1
		end
	end

--[[
	timer0 = timer0 + 1
	local id = avatar.GetTarget()
	if not id then
		if lastId then
			despawned( lastId )
			--spawned( lastId )
		end
		return
	else
		lastId = id
	end
	local wt = widgets[ id ]
	local healthbar = wt:GetChildChecked("HealthBar", false)
	--LogInfo ( timer0 )
	if timer0 == 3 then
		HPbarSize( healthbar, id, 10)
	elseif timer0 == 8 then
		HPbarSize( healthbar, id, 95)
	elseif timer0 == 10 then
		HPbarSize( healthbar, id, 10)
	elseif timer0 == 18 then
		HPbarSize( healthbar, id, 95)
	elseif timer0 > 20 then
		timer0 = 0
	end
]]

end

onEvent.EVENT_AVATAR_USED_OBJECT_CHANGED = function( pars )
	--if not Me or not widgets[Me] then return end
	local info = avatar.GetActiveUsableDeviceInfo()
	--exObj("dev",info)
	--local newDev = info and device.GetUsableDeviceType(info.id)
	if Me and widgets[Me] then
		if info then widgets[Me]:Show( false )
		else widgets[Me]:Show( true )
		end
	else
		Me = avatar.GetId()
		MyLVL = unit.GetLevel( Me )
		MyGuild = GetGuildName(Me)
		CreateNPB_My_Plate()
	end
end



local dSX, dTX, OLDplace = 160, 1.3
onEvent.EVENT_INGAME_UNDER_CURSOR_CHANGED = function( pars )
--[[
EVENT_INGAME_UNDER_CURSOR_CHANGED

Событие присылается при изменении объекта под курсором.

поля:

state: string - может принимать следующие значения:

- "interface" - курсор находится над элементом интерфейса, кроме основного 3d-view

- "main_view_3d_none" - курсор находится на основном 3d-view, под ним нет юнитов

- "main_view_3d_unit" - курсор находится на основном 3d-view, под ним находится юнит
  Для этого случая присылается дополнительное поле:
  unitId: ObjectId (not nil) - идентификатор юнита под курсором

- "main_view_3d_device" - курсор находится на основном 3d-view, под ним находится устройство (не юниты, сундуки и пр.)
  Для этого случая присылаются дополнительные поля:
  deviceId: ObjectId (not nil) - идентификатор устройства под курсором
  canUse: boolean - можно ли использовать устройство в текущий момент (в частности, учитывается расстояние до него)

- "main_view_3d_astral_unit" - курсор находится на основном 3d-view, под ним находится астральный юнит
  Для этого случая присылается дополнительное поле:
  unitId: ObjectId (not nil) - идентификатор астрального юнита под курсором

- "main_view_3d_interactive_device_element" - курсор находится на интерактивном элементе какого-либо устройства, при работе с этим устройством.
  Для этого случая присылается дополнительные поля:
  deviceType: number (enum USDEV_...) - тип корабельного устройства
  Если это USDEV_SCANER, то дополнительные поля:
  type: number (enum HT_...) - тип хаба {HT_NONE, HT_UNKNOWN, HT_OUR, HT_ENEMYSHIP, HT_PORTAL, HT_ALLOD, HT_ISLAND}
  name: WString or nil - название хаба, если это HT_PORTAL
]]
	local n
	--- сперва уберем с того на ком уже было
	if highLightedID and object.IsExist( highLightedID ) then
		local wt = widgets[highLightedID]
		if wt then
			object.Highlight( highLightedID, "SELECTION", nil, nil, 0 )
			highLightedID = nil
			if fadeNPB then wt:SetFade( fadeNPB) end
			if get_PS("selMouse") ~= OFF then
				--exObj2("highLightedID_FONTS", highLightedID_FONTS )
				local frmt
				for key, style in pairs(highLightedID_FONTS) do
					W( key, wt ):SetFormat(ToWS(makeFontFormatFromTab( style )))
				end

				wtResize(W("Icon",wt), -dSX*0.2, -dSX*0.2 )
				wtResize(W("panClass",wt), -dSX*0.2, -dSX*0.2 )
				wtSetPlace(wt, OLDplace )
			end
		end
	end
	if pars.state == "main_view_3d_unit" then
		highLightedID = pars.unitId
		local id = highLightedID
		local redColor = { r = 1, g = 1, b = 1, a = 0.4 }
		object.Highlight( id, "SELECTION", redColor, {}, 0 )
		local wt = widgets[id]
		if wt then
			wt:SetFade(1)
			if get_PS("selMouse") ~= OFF then
				local tt, ext = GET_UNIT_TYPE( id )
				local key, temp
				if unit.IsPlayer( id ) then
					highLightedID_FONTS.Name = getNameStyle(tt, id, ext)
					highLightedID_FONTS.TargName = getTargNameStyle(tt, id, ext)
					highLightedID_FONTS.Level = getLevelStyle(tt, id)
					highLightedID_FONTS.Title = getTitleStyle(tt, id, ext)
					highLightedID_FONTS.Title1 = getTitle1Style(tt, id, ext)
				else
					highLightedID_FONTS.Name = getNameStyle(tt, id, ext)
					highLightedID_FONTS.TargName = getTargNameStyle(tt, id, ext)
					highLightedID_FONTS.Level = getLevelStyle(tt, id)
					highLightedID_FONTS.Title = getTitleStyle(tt, id, ext)
					highLightedID_FONTS.Title1 = getTitle1Style(tt, id, ext)
				end
				for k, v in pairs(highLightedID_FONTS) do
					temp = Clone( v )
					--exObj2(key, temp)
					temp.fontsize = temp.fontsize + 5
					W(k, wt ):SetFormat(ToWS(makeFontFormatFromTab( temp )))
				end

			--W("Name",wt):SetTextScale( dTX ) --- плохо работает с ТИТЛАМИ ((

			wtResize(W("Icon",wt), dSX*0.2, dSX*0.2 )
			wtResize(W("panClass",wt), dSX*0.2, dSX*0.2 )

			OLDplace = wt:GetPlacementPlain()
			wtResize(wt, dSX*1, dSX/2 )
			--HPsizeXOld = W("HealthBar",wt):GetPlacementPlain().sizeX
			--wtSetPlace(W("HealthBar",wt), { posX = dSX/2, highPosX = dSX/2 } )
			end
		end
	end
end

onEvent.EVENT_PLAYER_TITLE_CHANGED = function( pars )
	PlayerTitleShow(GET_UNIT_TYPE( pars.id ), pars.id)
end

onEvent.EVENT_UNIT_DEAD_CHANGED = function( pars )
	showDead( pars.unitId )
end


--[[
onEvent.EVENT_UNIT_DAMAGE_RECEIVED = function( pars )

	--local sourceId = pars.source
	local id = pars.target

	if id and object.IsUnit( id ) then
		if false then
			pars.amount * 20 > 
		end

end
]]

--[[onEvent.EVENT_PICK_OBJECT = function( pars )
	exObj("EVENT_PICK_OBJECT", pars)
	LogToChat("EVENT_PICK_OBJECT")
end]]

--[[onEvent.EVENT_VALUED_OBJECT_MOUSEOVER = function( pars )
	exObj("EVENT_VALUED_OBJECT_MOUSEOVER", pars)
	LogToChat("EVENT_VALUED_OBJECT_MOUSEOVER")
end]]

--[[onEvent.EVENT_AVATAR_SECONDARY_TARGET_CHANGED = function( pars )
	exObj("EVENT_AVATAR_SECONDARY_TARGET_CHANGED", pars)
	LogToChat("EVENT_AVATAR_SECONDARY_TARGET_CHANGED")
end]]

--[[
-- иконки у дающего задания и так меняются!
-- похоже это не от заданияй случается
onEvent.EVENT_QUEST_BOOK_CHANGED = function( pars )
	exObj("EVENT_QUEST_BOOK_CHANGED", pars)
	LogToChat("EVENT_QUEST_BOOK_CHANGED")
	for id in pairs(widgets) do
		UnitDespawned( { unitId = id } )
	end
	for i, id in pairs(GetUnitList()) do
		CreateNPB(id)
	end

	
end
]]

--[[
--- это событие вообще приходит безо всяких квесто и не по делу - мобы вокруг обычные а оно на них приходит!
onEvent.EVENT_QUEST_MARK_UPDATED = function( pars )
-- сюда приходит исправно по мобам которым надо поменять ТИТЛЕ но серверне успевает инфо квестовости поменять ((
--- всё равно это событие не срабатывает нехрена
-- видимо по тойже причине что сервер выдает инфо актуальную позже чем я прорисую
-- пороще тогда с задержкой всех перерисовывать (см. ниже
	exObj2("EVENT_QUEST_MARK_UPDATED objectId", pars )
	local id = pars.objectId
	LogToChat("QUEST_MARK_UPDATED "..FromWS(object.GetName(id)))
	--repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
	if not object.IsExist( id ) then 
		--LogInfo("not exist")
		return
	end
	if object.IsUnit( id ) then
		--LogInfo("IsUnit")
		TitleShow( id )
	elseif object.IsDevice( id ) then
		--LogInfo("IsDevicw")
		onEvent_EVENT_DEVICE_SPAWNED( { id = id } )
	else
		--LogInfo("Is && type")
	end
--- тогда запустим так же с задержкой и будет 1 раз перестроение всего
	--repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end
]]


onEvent.EVENT_QUEST_OBJECTIVE_UPDATED = function( pars )
	--exObj2("EVENT_QUEST_OBJECTIVE_UPDATED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end


onEvent.EVENT_QUEST_COMPLETED = function( pars )
	--LogInfo("EVENT_QUEST_COMPLETED", pars.questId )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end
onEvent.EVENT_QUEST_DISCARDED = function( pars )
	--LogInfo("EVENT_QUEST_DISCARDED", pars )
	--- тут норм срабатывает - юниты неквестовые становятся при отказе
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end

onEvent.EVENT_QUEST_UPDATED = function( pars )
	--LogInfo("EVENT_QUEST_UPDATED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end
onEvent.EVENT_QUEST_FAILED = function( pars )
	--LogInfo("EVENT_QUEST_FAILED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end


onEvent.EVENT_CURRENT_QUEST_CHANGED = function( pars )
	--LogInfo("EVENT_CURRENT_QUEST_CHANGED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end

onEvent.EVENT_QUEST_READY_TO_RETURN_CHANGED = function( pars )
	--LogInfo("EVENT_QUEST_READY_TO_RETURN_CHANGED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end

--[[ эти события дублируются событием EVENT_QUEST_BOOK_CHANGED
onEvent.EVENT_QUEST_RECEIVED = function( pars )
	LogInfo("EVENT_QUEST_RECEIVED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end
onEvent.EVENT_QUEST_ABANDONED = function( pars )
	LogInfo("EVENT_QUEST_ABANDONED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end
]]

--- сюда приходит при измении в квестах
onEvent.EVENT_QUEST_BOOK_CHANGED = function( pars )
	--- при выполнении подпункта меню сюда вообще не приходит
	--LogInfo("EVENT_QUEST_BOOK_CHANGED", pars )
	repaint0 = 1 --- оказывает при изменении КВЕСТА сервер не успевает инфо на мобах поменять! надо с задержкой запускать перерисовку!
end



--------------------------------------------------------------------------------
-- INITIALIZATION
--------------------------------------------------------------------------------
function repaint_all()

	for id in pairs(widgets) do
		despawned( id )
	end

	Me = avatar.GetId() --- icreator
	MyLVL = unit.GetLevel( Me )
	MyGuild = GetGuildName(Me)
	CreateNPB_My_Plate()

	local lst = GetUnitList()
	--exObj("GetUnitList()", lst )
	for i, id in pairs(lst) do
		CreateNPB(id)
	end
	for _, id in pairs(avatar.GetDeviceList()) do
		onEvent_EVENT_DEVICE_SPAWNED( { id = id } )
	end

	onGroupChanged()
	onRaidChanged()

end

function InitNPB2()

--[[
		local dt = GetLocalDateYMD()
		if not dt then mission.GetLocalDate()() end --- вызовем ошибку
		if not dt or dTot.y <= dt.y and dTot.m <= dt.m and dTot.d < dt.d then
			getSetPanel():Enable( false )
			LogToChat("Please update me")
			return
		end
--]]
	RUN = true --- запустились
	fadeNPB = tonumber(get_PS("fadeNPB"))

	local npb0 = mainForm:GetChildChecked("NamePlateBar", false)
	local wtClass = npb0:GetChildChecked("Icon", false)
	local wtIcon = npb0:GetChildChecked("panClass", false)

	if not _PS.iconPlace then _PS.iconPlace = wtIcon:GetPlacementPlain() end
	if not _PS.classPlace then _PS.classPlace = wtClass:GetPlacementPlain() end

	Me = avatar.GetId() --- icreator
	MyLVL = unit.GetLevel( Me )
	MyGuild = GetGuildName(Me)
	setMyGuild( Me )

	CreateNPB_My_Plate()

	--exObj2("GetUnitList()", GetUnitList() )
	for i, id in pairs(GetUnitList()) do
		CreateNPB(id)
	end
	for _, id in pairs(avatar.GetDeviceList()) do
		onEvent_EVENT_DEVICE_SPAWNED( { id = id } )
	end

	common.RegisterEventHandler(Detect, "EVENT_OBJECT_DETECT_STARTED")
	common.RegisterEventHandler(Detect, "EVENT_OBJECT_DETECT_FINISHED")
	common.RegisterEventHandler(RelationChanged, "EVENT_UNIT_RELATION_CHANGED")
	common.RegisterEventHandler(NameChanged, "EVENT_UNIT_NAME_CHANGED") --- before v. 4.0.01
	common.RegisterEventHandler(NameChanged, "EVENT_OBJECT_NAME_CHANGED")
	common.RegisterEventHandler(UnitHPercChanged, "EVENT_UNIT_HEALTH_PERCENTAGE_CHANGED")
	common.RegisterEventHandler(UnitHPercChanged, "EVENT_UNIT_HEALTH_CHANGED")
	common.RegisterEventHandler(UnitHPercChanged, "EVENT_OBJECT_HEALTH_CHANGED")
	common.RegisterEventHandler(DetectChanged, "EVENT_OBJECT_DETECTOR_LIST_CHANGED")
	common.RegisterEventHandler(LevelChanged, "EVENT_UNIT_LEVEL_CHANGED")
	common.RegisterEventHandler(TagChanged, "EVENT_UNIT_TAG_CHANGED")
	common.RegisterEventHandler(GuildChanged, "EVENT_GUILD_CHANGED")
 	common.RegisterEventHandler( onGroupChanged, "EVENT_GROUP_CHANGED" )
 	common.RegisterEventHandler( onRaidChanged, "EVENT_RAID_CHANGED" )
	--common.RegisterEventHandler(Slash, "EVENT_UNKNOWN_SLASH_COMMAND")
 	common.RegisterEventHandler( onEmoteText, "EVENT_EMOTE_TEXT" )
 	--common.RegisterEventHandler( onEVENT_UNIT_MOOD_CHANGED, "EVENT_UNIT_MOOD_CHANGED" )

 	common.RegisterEventHandler( onEvent_EVENT_DEVICE_SPAWNED, "EVENT_DEVICE_SPAWNED" )
 	common.RegisterEventHandler( onEvent_EVENT_DEVICE_DESPAWNED, "EVENT_DEVICE_DESPAWNED" )

	RegisterEventHandlers( onEvent )

end

--- так как avatar.GetUnitList теперь не работает то будем сразу запоминать
	--common.RegisterEventHandler(UnitsChanged, "EVENT_UNITS_CHANGED")
	common.RegisterEventHandler(UnitSpawned, "EVENT_UNIT_SPAWNED")
	common.RegisterEventHandler(UnitDespawned, "EVENT_UNIT_DESPAWNED")


--if avatar.IsExist() then onAvatarCreated() --- для инициализации при загрузке/выгрузке
--else common.RegisterEventHandler( onAvatarCreated, "EVENT_AVATAR_CREATED" ) end
