class NPCManager extends IScriptable
{
	private var m_owner : weak< NPCPuppet >;

	public function Init( owner : GameObject )
	{
		var record : weak< Character_Record >;
		if( !( owner ) )
		{
			return;
		}
		m_owner = ( ( NPCPuppet )( owner ) );
		record = TweakDBInterface.GetCharacterRecord( m_owner.GetRecordID() );
		if( record.GetTagsCount() > 0 )
		{
			SetNPCImmortalityMode( record );
		}
		if( record.GetOnSpawnGLPsCount() > 0 )
		{
			ApplySpawnGLPs( record, false );
		}
		if( record.GetAbilitiesCount() > 0 )
		{
			SetNPCAbilities( record );
		}
		SetNPCVisualTagsStats( record );
		SetNPCArchetypeData( record );
	}

	public function ApplySpawnAnimWrappers()
	{
		var record : weak< Character_Record >;
		if( !( m_owner ) )
		{
			return;
		}
		record = TweakDBInterface.GetCharacterRecord( m_owner.GetRecordID() );
		if( record.GetOnSpawnGLPsCount() > 0 )
		{
			ApplySpawnGLPs( record, true );
		}
	}

	public function UnInit( owner : GameObject )
	{
		ClearNPCImmortalityMode();
	}

	private function ApplySpawnGLPs( record : weak< Character_Record >, applyAnimWrappers : Bool )
	{
		var spawnGLPs : array< weak< GameplayLogicPackage_Record > >;
		record.OnSpawnGLPs( spawnGLPs );
		RPGManager.ApplyGLPArray( m_owner, spawnGLPs, true, ( ( applyAnimWrappers ) ? ( 1 ) : ( -1 ) ) );
	}

	private function SetNPCAbilities( record : weak< Character_Record > )
	{
		var abilities : array< weak< GameplayAbility_Record > >;
		record.Abilities( abilities );
		RPGManager.ApplyAbilityArray( m_owner, abilities );
	}

	private function SetNPCVisualTagsStats( record : weak< Character_Record > )
	{
		var statSys : StatsSystem;
		var modifier : gameStatModifierData;
		if( m_owner.IsMassive() )
		{
			statSys = GameInstance.GetStatsSystem( m_owner.GetGame() );
			modifier = RPGManager.CreateStatModifier( gamedataStatType.IsManMassive, gameStatModifierType.Additive, 1.0 );
			statSys.AddModifier( m_owner.GetEntityID(), modifier );
		}
		if( NPCManager.HasVisualTag( m_owner, 'Big' ) )
		{
			statSys = GameInstance.GetStatsSystem( m_owner.GetGame() );
			modifier = RPGManager.CreateStatModifier( gamedataStatType.IsManBig, gameStatModifierType.Additive, 1.0 );
			statSys.AddModifier( m_owner.GetEntityID(), modifier );
		}
	}

	private function SetNPCArchetypeData( record : weak< Character_Record > )
	{
		var i : Int32;
		var statGroups : array< weak< StatModifierGroup_Record > >;
		var abilityGroups : array< weak< GameplayAbilityGroup_Record > >;
		var archetypeData : weak< ArchetypeData_Record >;
		archetypeData = record.ArchetypeData();
		if( !( archetypeData ) )
		{
			return;
		}
		if( archetypeData.GetStatModifierGroupsCount() > 0 )
		{
			archetypeData.StatModifierGroups( statGroups );
			RPGManager.ApplyStatModifierGroups( m_owner, statGroups );
		}
		if( archetypeData.GetAbilityGroupsCount() > 0 )
		{
			archetypeData.AbilityGroups( abilityGroups );
			for( i = 0; i < abilityGroups.Size(); i += 1 )
			{
				RPGManager.ApplyAbilityGroup( m_owner, abilityGroups[ i ] );
			}
		}
	}

	private function ScaleToPlayer()
	{
		var statSys : StatsSystem;
		var playerPL : Float;
		var playerLevel : Float;
		var modifier : gameStatModifierData;
		statSys = GameInstance.GetStatsSystem( m_owner.GetGame() );
		statSys.RemoveAllModifiers( m_owner.GetEntityID(), gamedataStatType.PowerLevel );
		playerPL = statSys.GetStatValue( GameInstance.GetPlayerSystem( m_owner.GetGame() ).GetLocalPlayerControlledGameObject().GetEntityID(), gamedataStatType.PowerLevel );
		playerLevel = statSys.GetStatValue( GameInstance.GetPlayerSystem( m_owner.GetGame() ).GetLocalPlayerControlledGameObject().GetEntityID(), gamedataStatType.Level );
		modifier = RPGManager.CreateStatModifier( gamedataStatType.PowerLevel, gameStatModifierType.Additive, playerPL );
		statSys.AddModifier( m_owner.GetEntityID(), modifier );
		modifier = RPGManager.CreateStatModifier( gamedataStatType.Level, gameStatModifierType.Additive, playerLevel );
		statSys.AddModifier( m_owner.GetEntityID(), modifier );
	}

	private function SetNPCImmortalityMode( record : weak< Character_Record > )
	{
		var tags : array< CName >;
		tags = record.Tags();
		if( tags.Contains( EnumValueToName( 'gameGodModeType', ( ( Int64 )( gameGodModeType.Invulnerable ) ) ) ) )
		{
			GameInstance.GetGodModeSystem( m_owner.GetGame() ).AddGodMode( m_owner.GetEntityID(), gameGodModeType.Invulnerable, 'Default' );
		}
		else if( tags.Contains( EnumValueToName( 'gameGodModeType', ( ( Int64 )( gameGodModeType.Immortal ) ) ) ) )
		{
			GameInstance.GetGodModeSystem( m_owner.GetGame() ).AddGodMode( m_owner.GetEntityID(), gameGodModeType.Immortal, 'Default' );
		}
	}

	private function ClearNPCImmortalityMode()
	{
		GameInstance.GetGodModeSystem( m_owner.GetGame() ).ClearGodMode( m_owner.GetEntityID(), 'Default' );
	}

	public static function HasTag( recordID : TweakDBID, tag : CName ) : Bool
	{
		var tags : array< CName >;
		tags = TweakDBInterface.GetCharacterRecord( recordID ).Tags();
		if( tags.Contains( tag ) )
		{
			return true;
		}
		return false;
	}

	public static function HasAnyTags( recordID : TweakDBID, const tags : ref< array< CName > > ) : Bool
	{
		var i : Int32;
		if( tags.Size() <= 0 )
		{
			return false;
		}
		for( i = 0; i < tags.Size(); i += 1 )
		{
			if( HasTag( recordID, tags[ i ] ) )
			{
				return true;
			}
		}
		return false;
	}

	public static function HasAllTags( recordID : TweakDBID, const tags : ref< array< CName > > ) : Bool
	{
		var i : Int32;
		if( tags.Size() <= 0 )
		{
			return false;
		}
		for( i = 0; i < tags.Size(); i += 1 )
		{
			if( !( HasTag( recordID, tags[ i ] ) ) )
			{
				return false;
			}
		}
		return true;
	}

	public static function HasVisualTag( puppet : weak< ScriptedPuppet >, visualTag : CName ) : Bool
	{
		if( !( puppet ) || !( IsNameValid( visualTag ) ) )
		{
			return false;
		}
		if( puppet.MatchVisualTag( visualTag ) )
		{
			return true;
		}
		return false;
	}

	public static function HasAllVisualTags( puppet : weak< ScriptedPuppet >, const visualTags : ref< array< CName > > ) : Bool
	{
		if( !( puppet ) || ( visualTags.Size() <= 0 ) )
		{
			return false;
		}
		return puppet.MatchVisualTags( visualTags );
	}

	public static function HasAnyVisualTags( puppet : weak< ScriptedPuppet >, const visualTags : ref< array< CName > > ) : Bool
	{
		var i : Int32;
		if( !( puppet ) || ( visualTags.Size() <= 0 ) )
		{
			return false;
		}
		for( i = 0; i < visualTags.Size(); i += 1 )
		{
			if( puppet.MatchVisualTag( visualTags[ i ] ) )
			{
				return true;
			}
		}
		return false;
	}

}

