// -----------------------------------------------------------------------------------------------------------------------
/*
	The base class of all level scripts.
	There are two important parts in this class:

	1. Important variables:
		Variables that are written down here to keep the whole system clearly arranged. There is no technical
		usage to have them here, but with multiple scripters at the same time it's quite handy to have them 
		in one place.
	
	2. Useful basic functions:
		Functions that are quite handy, and are not provided by the programmers themselv. 
		Example is the SetHeroParty() function, which sets the hero party dynamically to the given level. 
		There are many other practical functions, give them a look. 
	
*/
#include "../../basicScripts/LevelBase_Gameplay.as"
#include "../../basicScripts/LevelBase_Tutorials.as" 
#include "../../basicScripts/LevelBase_WorldState.as"
#include "../../basicScripts/LevelBase_Achievements.as"

// -----------------------------------------------------------------------------------------------------------------------

enum MusicIntensity
{
	normal = 	0,
	low = 		100,
	med = 		500,
	high = 		1000
}

class LevelBase : LevelBase_Gameplay, LevelBase_Tutorials, LevelBase_WorldState, LevelBase_Achievements
{
	// -------------------------------------------------------------------------------------------------------------------
	string m_LevelBaseVersion = "0.292 - 07.12.2017 - 18:09"; // ANJA - end me please q.q
	//string m_LevelBaseVersion = "0.292 - 07.12.2017 - 16:48"; // KEVIN
	//string m_LevelBaseVersion = "0.290 - 07.12.2017 - 12:34"; // ANJA
	//string m_LevelBaseVersion = "0.289 - 06.12.2017 - 20:37";
	//string m_LevelBaseVersion = "0.288 - 05.12.2017 - 20:46";
	
	
	// -------------------------------------------------------------------------------------------------------------------
	// variables:
	protected LevelReference@ m_Reference = null;
	
	// -------------------------------------------------------------------------------------------------------------------
	// public variables:
	
	string m_stgEntrance_WorldMap = "PlayerSpawn_WorldMap";
	bool m_stgIsCampaignMap = 		true; 
	
	// configuration for the revealing functions
	uint m_iRevealTime = 			5;
	uint m_iRevealCondition = 		10001;
	
	// basic configurations
	uint m_iPlayerFaction = 		0;
	uint m_iMaxFactions = 			13;

	bool m_bIntro = 				true;
	bool m_bUsePlayerSpawn = 		true;
	int m_iMarkerSightRange = 		200;

	bool m_b_BossMusicPlaying = 	false;

	array <string> m_arrEquipmentSlots = { 'PrimaryHand', 'SecondaryHand', 'Head', 'Neck', 'Torso', 'Ring1', 'Ring2', 'Item' };
	
	// -------------------------------------------------------------------------------------------------------------------
	// --- Blueprint & Description Information's -------------------------------------------------------------------------

	array <string> m_arrStg_MP_Heroes = { "MP_Hero_Archer", "MP_Hero_BlackMage", "MP_Hero_Elementalist", "MP_Hero_Engineer", "MP_Hero_Marauder", "MP_Hero_Paladin", "MP_Hero_WhiteMage" };
	

	array <string> m_arrStg_Races = { "O_", "H_", "E_" };

	array <string> m_arrStg_Worker = { "E_Henchman", "E_MarketCarriage", "E_SettlerCarriage", "H_Henchman", "H_MarketCarriage", "H_SettlerCarriage", "O_Henchman", "O_MarketCarriage", "O_SettlerCarriage" };

	array <string> m_arrStg_Units_H = { "H_Armsman", "H_Catapult", "H_Helebardier", "H_Marksman", "H_Mentalist", "H_Paladin", "H_Pillager", "H_Recruit", "H_Scout", "H_Soldier", "H_Titan" };
	array <string> m_arrStg_Units_E = { "E_Ballista", "E_Druid", "E_Guardian", "E_Novice", "E_Pathfinder", "E_Protector", "E_Ranger", "E_Titan", "E_Wanderer", "E_Warder", "E_Wintermage" };
	array <string> m_arrStg_Units_O = { "O_Drummer", "O_Fighter", "O_Firemaster", "O_Marauder", "O_Mercenary", "O_Pikeman", "O_SiegeTroll", "O_Thug", "O_Titan", "O_Troll", "O_Wargrider" };

	array <string> m_arrStg_Bldgs_H = { "H_Academy", "H_Aria_Collector", "H_Aria_Distillery", "H_Barracks_I",
		 "H_Farm", "H_Fishing_Cabin", "H_Hunting_Cabin", "H_Iron_Mine", "H_Iron_Smeltery", "H_Smith", 
		 "H_Stone_Tower", "H_Stonecutter", "H_Woodcutter", "H_Wooden_Tower", "H_Wooden_Tower_II", "H_Wooden_Tower_III" 
	 };
	array <string> m_arrStg_Bldgs_E = { "E_Arcanesmith", "E_Barracks_I", "E_Farm", "E_Fishing_Cabin",
		 "E_Heart_of_the_Forest", "E_Hunting_Cabin", "E_Iron_Mine", "E_Iron_Smeltery", "E_Lenya_Collector", "E_Lenya_Processor", 
		 "E_Shrine", "E_Stonecutter", "E_Woodcutter", "E_Wooden_Tower", "E_Wooden_Tower_II", "E_Wooden_Tower_III"  
	};
	array <string> m_arrStg_Bldgs_O = { "O_Barracks_I", "O_BlackAsh_Collector", "O_BlackAsh_Processor", "O_Dark_Forge",
		 "O_Farm", "O_Fishing_Cabin", "O_Hunting_Cabin", "O_Iron_Mine", "O_Iron_Smeltery", "O_Stonecutter", 
		 "O_Warsmith", "O_Wartotem", "O_Woodcutter", "O_Wooden_Tower", "O_Wooden_Tower_II", "O_Wooden_Tower_III"  
	};
	
// Old, old legacy stuff
// ***  only here, because savegames cry around, if this stuff is gone ....
	array <dictionary> m_arrQueue_DialogTalkGathered;
	array <dictionary> m_arrQueue_ShoutoutGathered;
	dictionary m_dictEquippment;
	dictionary m_dictQueue_ShoutoutChecked;
	dictionary m_dictQueue_ShoutoutOutOfCombat;
	dictionary m_dictQueue_ShoutoutTimed;
	dictionary m_dictQueue_ShoutoutTimedAndReady;

	string m_glbCat_Equiping;
	string m_glbCat_GK2_equipment;
	string m_glbCat_GK2_inventory;

	uint m_iShoutoutWait;
	uint m_iShoutoutWait_long;

	dictionary m_deictBanternInformations;
	uint m_iCurrentBanternPosition;
// *** 

	
	// --------------------------------------------------------------------------------------------------------------------
	// --- C O N S T R U C T O R ------------------------------------------------------------------------------------------
	LevelBase (LevelReference@ _Reference)
	{
		@m_Reference = _Reference;
	}

	// -------------------------------------------------------------------------------------------------------------------
	// --- B A S I C   F U N C T I O N S  ---------------------------------------------------------------------------------

	// level is being created for the first time - only called once for a campaign
	void OnCreated ()
	{
		if ( m_stgIsCampaignMap )
		{
			//printImportant("V E R S I O N : LevelBase: "+m_LevelBaseVersion+".");//, Map Script: " + m_stgVersion+" (Level was just created)");
			//printImportant("M A P : Map: "+ m_Reference.GetMapId() +", setting: " + m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) +" and '"+GetCurrentMapInformation()+"'.");
			//printNote("Debugging Mode: Are win in debugging?"+ m_bDebuggingMode); <- this is already printed in WorldState
			
			SetWorldState();
			ConfigureRaceSelection();
			
			RegisterEvents_Tutorial_basic();

			//m_bDebuggingMode = m_Reference.GetWorld().GetGlobalBool( m_glbCat_Map+"_DEBUGGING_", false );

			// Handling special maps 
			//if ( m_Reference.GetMapId() == uint(m_iMap_CC) || m_Reference.GetMapId() ==  uint(m_iMap_WM) )
			if ( GetCurrentMapString() == "S_CC" || GetCurrentMapString() == "S_WM")
				// FOR DEBUGGING - to disable all following skilling of the hero party
				m_Reference.GetWorld().SetGlobalBool( m_glbCat_Map+"_DEBUGGING_HeroPartySet", true );
			
			// Handle all the normal maps
			else 
			{
				// Handle NPCs
				SetWorldState_Traders();
				Travel_HandleMapTransitions();
				ConfigureWorldMap();
				ConfigureHeros();

				// AF - Stuff
				//CheatIsgrimmItems();
				//CheckCpmanionQuests();
				//Check_IsgrimmItems(); // Inserted
				
				// Handle the PlayerSpawn - only in normal maps, not in WorldMap or Character creator
				if (m_bDebuggingMode)
				{
					// exclude the Mulandir maps from this. 
					if( GetCurrentMapInformation() != "M2" && GetCurrentMapInformation() != "M3" && GetCurrentMapInformation() != "AF1" && GetCurrentMapInformation() != "AF_T2" )
					{
						// Handle the debug hero/player spawns spawns
						if ( m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 0 )
							m_Reference.ActivateSpawn( "PlayerSpawn_0", true);
						else if ( m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 1 )
							m_Reference.ActivateSpawn( "PlayerSpawn_1", true);
						else if ( m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 2 )
							m_Reference.ActivateSpawn( "PlayerSpawn_2", true);
						else if ( m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 3 )
							m_Reference.ActivateSpawn( "PlayerSpawn_3", true);
						else if ( m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 4 )
							m_Reference.ActivateSpawn( "PlayerSpawn_4", true);
						else if ( m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 5 )
							m_Reference.ActivateSpawn( "PlayerSpawn_5", true);
					}

					// add debug skilltrees
					m_Reference.GetHeroParty(m_iPlayerFaction).SelectAvatarAbilityTree("Tree_DPS");
					m_Reference.GetHeroParty(m_iPlayerFaction).SelectAvatarAbilityTree("Tree_Black");
					m_Reference.GetHeroParty(m_iPlayerFaction).SelectAvatarAbilityTree("Tree_White");

					// level up player 
					SetHeroParty(1);
				}

				
				
				
				if ( m_bIntro )
				{
					// Handle the Map Intro - if it exists thou
					if ( m_Reference.GetWorld().DoesDialogueTopicExist( m_stgAvatar, "MapIntro_1" ) && m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 0 )
						DialogShoutout( m_stgAvatar, m_stgAvatar, "MapIntro_1", true );
					else if ( m_Reference.GetWorld().DoesDialogueTopicExist( m_stgAvatar, "MapIntro_2" ) &&  m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 1 )
						DialogShoutout( m_stgAvatar, m_stgAvatar, "MapIntro_2", true );
					else if ( m_Reference.GetWorld().DoesDialogueTopicExist( m_stgAvatar, "MapIntro_3" ) &&  m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) == 2 )
						DialogShoutout( m_stgAvatar, m_stgAvatar, "MapIntro_3", true );
				}

				
				// Register gameplay relevant events like the revive talisman or reskill potion
				RegisterEvents_Gameplay();

				// Handle WorldMap stuff
				// Set the last map visited to the current one: 
				m_Reference.GetWorld().SetGlobalInt( m_stgWorld_LastVisited, m_Reference.GetMapId() );
				
				// Handle that the Hero party does not wiggle around ...
				HeroPartyGatherAtFirst();
				//HUB_AffinityQuest_DisableAbility_Party();

				// and setup the RTS gameplay, if there is RTS
				SetupPlayerRTS();
				
				// Hero Bantern, was sorted out and is not used currently :'( 
				// but dont delete it, it's going to come back sometime
				//m_Reference.SetTimer( TOnTimerEvent(@this.HeroBantern), (m_Reference.GetRandom().GetInteger( m_iBanternTime_Min, m_iBanternTime_Max ) + m_iBanternTime_IntroPuffer) );
				//m_Reference.
			}
		}
	}

	// level data had been restored from savegame - ensure version compability here
	void OnLoaded ( const uint _uVersion )
	{
		if ( m_stgIsCampaignMap )
		{
			if ( GetCurrentMapString() != "S_CC" || GetCurrentMapString() != "S_WM")
			{
				//if( m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers()[0].Exists() )
				//	m_Reference.FocusCamera( m_iPlayerFaction, m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers()[0] );
				ConfigureWorldMap();
				ConfigureHeros();
			}

			// Set the last map visited to the current one: 
			m_Reference.GetWorld().SetGlobalInt( m_stgWorld_LastVisited, m_Reference.GetMapId() );

		}
	}

	// level has been entered
	void OnEntered ()
	{
		// do nothing here. Is not used.
	}

	// -------------------------------------------------------------------------------------------------------------------
	// --- D E B U G   F U N C T I O N S -------------------------------------------------------------------------------------
	
	void printImportant(string _stgDebug)
	{
		print(" *** " + _stgDebug);
	}

	void printNote(string _stgDebug)
	{
		print(" - [NOTE]: " + _stgDebug);
	}

	// to similar to printNote, we are not really needing this
	/*void printDebug(string _stgDebug)
	{
		print(" - DEBUG: " + _stgDebug);
	}*/

	void printArticy(string _stgDebug)
	{
		print(" - [ARTICY]: " + _stgDebug);
	}

	void printCheat(string _stgDebug)
	{
		print(" - [CHEAT]: " + _stgDebug);
	}

	void printCutscene(string _stgDebug)
	{
		print(" - [CUTSCENE]: " + _stgDebug);
	}

	void printGameplay(string _stgDebug)
	{
		print(" - [GAMEPLAY]: " + _stgDebug);
	}

	void printDialog(string _stgDebug)
	{
		print(" - [DIALOG]: " + _stgDebug);
	}
	


	void printWorld(string _stgDebug)
	{
		print(" - [WORLD]: " + _stgDebug);
	}

	// -------------------------------------------------------------------------------------------------------------------
	// --- M A P  T R A V E L I N G  F U N C T I O N S  ------------------------------------------------------------------

	string GetCurrentMapInformation()
	{
		// get the current map, current setting - and then the current 
		string _stgMapAndSetting = "";
		m_dictMapAcronyms.get( ""+m_Reference.GetMapId(), _stgMapAndSetting );
		_stgMapAndSetting +=  (m_Reference.GetWorld().GetCurrentMapSetting( m_Reference.GetMapId() ) )+1;

		return _stgMapAndSetting;
	}

	int GetMapID ( string _stgMap )
	{
		int _iMapId = 0;
		// first, get the damn Number to the Map string
		array <string> _arrKeys = m_dictMapAcronyms.getKeys();
		for( uint _iTmp = 0; _iTmp < _arrKeys.length() ; _iTmp++ )
		{
			string _stgTmp;
			m_dictMapAcronyms.get( _arrKeys[_iTmp], _stgTmp );
			if( _stgTmp == _stgMap )
			{
				_iMapId = parseInt( _arrKeys[_iTmp] );
				break; 
			}
		}
		return _iMapId;
	}

	string CheckFristMapID ( )
	{
		// check the started map. If it'c LC1, then the Game was started normally
		int _iStartedMap_ID = m_Reference.GetWorld().GetGlobalInt( m_stgWorld_FirstMap_ID, -1);
		int _iStartedMap_Setting  = m_Reference.GetWorld().GetGlobalInt( m_stgWorld_FirstMap_Setting, -1);

		if ( _iStartedMap_ID <= 0 ) // check first, if a first map was already registered
		{
			_iStartedMap_ID = m_Reference.GetMapId();
			_iStartedMap_Setting = m_Reference.GetWorld().GetCurrentMapSetting(_iStartedMap_ID);
			_iStartedMap_Setting++;
			m_Reference.GetWorld().SetGlobalInt( m_stgWorld_FirstMap_ID, _iStartedMap_ID);
			m_Reference.GetWorld().SetGlobalInt( m_stgWorld_FirstMap_Setting, _iStartedMap_Setting);
		}

		return GetMapString(_iStartedMap_ID)+_iStartedMap_Setting;
	}

	string GetMapString ( int _iTmp )
	{
		string _stgMap = "";
		m_dictMapAcronyms.get( ""+_iTmp, _stgMap);
		return _stgMap;
	}

	string GetCurrentMapString ()
	{
		string _stgMap = "";
		m_dictMapAcronyms.get( ""+m_Reference.GetMapId(), _stgMap);
		return _stgMap;
	}

	
	// -------------------------------------------------------------------------------------------------------------------
	// --- G E N E R A L   E V E N T S -----------------------------------------------------------------------------------

	bool OnDespawnCreature( Creature& in _Creature )
	{	
		printNote("Despawning creature "+_Creature.GetDescriptionName()+" ");
		_Creature.Enable(false);
		return true;
	}
	bool OnDespawnCreatureGroup( Creature& in _Creature )
	{	
		printNote("Despawning creature "+_Creature.GetDescriptionName()+" ");
		_Creature.Enable(false);
		return false;
	}

	void SpawnRevive( array <uint> m_arrTmp )
	{
		//array <Creature>@ _arrCrt = m_Reference.GetCreaturesFromSpawn( _stgSpawnName );
		for ( uint _iTmp = 0; _iTmp < m_arrTmp.length() ; _iTmp++ )
		{
			m_Reference.GetCreatureById( m_arrTmp[_iTmp] ).Revive();
		}
	}
	void SpawnDespawn( string _stgSpawnName )
	{
		array <Creature>@ _arrCrt = m_Reference.GetCreaturesFromSpawn( _stgSpawnName );
		for ( uint _iTmp = 0; _iTmp < _arrCrt.length() ; _iTmp++ )
			_arrCrt[_iTmp].Enable(false);
	}
	void SpawnKill( string _stgSpawnName )
	{
		CreatureGroup _crtGrp ( m_Reference );
		_crtGrp.Set( m_Reference.GetCreaturesFromSpawn( _stgSpawnName ) );
		_crtGrp.Die( false );		
	}
	void SpawnPreserve( string _stgSpawnName )
	{
		array <Creature>@ _arrCrt = m_Reference.GetCreaturesFromSpawn( _stgSpawnName );
		for ( uint _iTmp = 0; _iTmp < _arrCrt.length() ; _iTmp++ )
		{
			_arrCrt[_iTmp].SetPreserveBody( true );
		}
	}
	void SpawnKillAndPreserve( string _stgSpawnName )
	{
		array <Creature>@ _arrCrt = m_Reference.GetCreaturesFromSpawn( _stgSpawnName );
		for ( uint _iTmp = 0; _iTmp < _arrCrt.length() ; _iTmp++ )
		{
			_arrCrt[_iTmp].KillAndPreserve( m_Reference);
		}
	}
	void SpawnAttackable ( string _stgSpawn, bool _bEnable )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
		{
			_arrCrtTmp[_iTmp].SetAttackable(_bEnable);
		} 
	}
	void SpawnAllowAttacks ( string _stgSpawn, bool _bEnable )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
		{
			_arrCrtTmp[_iTmp].AllowAttacks(_bEnable);
		}
	}
	void SpawnReveal ( string _stgSpawn )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
			_arrCrtTmp[_iTmp].ApplyCondition( m_iRevealCondition, m_iRevealTime, m_iPlayerFaction );
	}
	bool IsSpawnAlive( string _stgSpawn )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
		{
			if( _arrCrtTmp[_iTmp].GetCurrentHP() > 0 )
				return true;
		}

		// RIP - Seems like all creatures belonging to this spawn are dead...
		return false;
	}
	
	// Custom teleport helper method
	void Teleport(string _stgCreatureName, string _stgEntityPositionName)
	{
		printNote("Teleporting " + _stgCreatureName + " to " + _stgEntityPositionName);
		Creature _crtObj = m_Reference.GetCreatureByName( _stgCreatureName );
		Entity _entTeleport = m_Reference.GetLogicObjectByName( _stgEntityPositionName );
		
		if( _entTeleport.Exists() && _crtObj.Exists() )
			_crtObj.Teleport( m_Reference, _entTeleport );
		else
			printNote("Teleport failed! Either a creature or an entity is invalid!");
	}

	array <Creature> GetNPCs( )
	{
		array <Creature> _arrNPCs; 
		for ( uint _iTmp1 = 0; _iTmp1 < m_iMaxFactions ; _iTmp1++ )
		{
			array <Creature> _arrNPC_tmp = m_Reference.FindCreaturesByType( _iTmp1, Character ) ;
			for ( uint _iTmp2 = 0; _iTmp2 < _arrNPC_tmp.length() ; _iTmp2++ )
			{
				//printNote( "*** tmp: "+_arrNPC_tmp[_iTmp2].GetDescriptionName() );
				_arrNPCs.insertLast( _arrNPC_tmp[_iTmp2] );
			}
		}
		return _arrNPCs;
	}
	array <Creature> GetNPCs_OtherFactions( uint _iFaction )
	{
		array <Creature> _arrNPCs; 
		for ( uint _iTmp1 = 0; _iTmp1 < m_iMaxFactions ; _iTmp1++ )
		{
			if ( _iTmp1 != _iFaction )
			{
				array <Creature> _arrNPC_tmp = m_Reference.FindCreaturesByType( _iTmp1, Character ) ;
				for ( uint _iTmp2 = 0; _iTmp2 < _arrNPC_tmp.length() ; _iTmp2++ )
				{
					//printNote( "*** tmp: "+_arrNPC_tmp[_iTmp2].GetDescriptionName() );
					_arrNPCs.insertLast( _arrNPC_tmp[_iTmp2] );
				}
			}
		}
		return _arrNPCs;
	}

	void TransferRTS ( uint _iFaction_A, uint _iFaction_B )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetHeroParty( _iFaction_A ).GetMembers();
		array <Building>@ _arrBldgGodstones = m_Reference.FindBuildingsByDescription( _iFaction_A, "S_Godstone" );
		
		m_Reference.TransferFactionAssets( _iFaction_A, _iFaction_B );
		
		// don't lose hero party and gostones
		for ( uint _iTmp = 0; _iTmp < _arrBldgGodstones.length(); _iTmp++ )
			_arrBldgGodstones[_iTmp].SetFaction( _iFaction_A );
		
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length(); _iTmp++ )
			_arrCrtTmp[_iTmp].SetFaction( _iFaction_A );


		if ( m_Reference.GetSectorsByOwner( m_iPlayerFaction ).length() > 0 )
			EnableWorldMap( false );
		else 
		{
			bool _bEnableOrNotEnable; // this is the question
			m_dictEnableWorldmap.get( GetCurrentMapInformation(), _bEnableOrNotEnable );
			EnableWorldMap( _bEnableOrNotEnable );
		}
	}


	/*void DespawnCreature ( string _stgCreatureName )
	{
		Creature _crtCreature = m_Reference.GetCreatureByName( _stgCreatureName );
		_crtCreature.SetPlayerControllable (false);
		_crtCreature.Enable(false);
	}*/
	
	/*array <Creature> GetDialogNPCs( uint _iFaction )
	{
		array <Creature> _arrHeroParty = m_Reference.GetHeroParty( _iFaction ).GetMembers();
		array <Creature> _arrNPCsWithDialogs; // = m_Reference.FindCreaturesByType( , _Type) ;
		for ( uint _iTmp1 = 0; _iTmp1 < m_iMaxFactions ; _iTmp1++ )
		{
			array <Creature> _arrNPC_tmp = m_Reference.FindCreaturesByType( _iTmp1, Character ) ;
			for ( uint _iTmp2 = 0; _iTmp2 < _arrNPC_tmp.length() ; _iTmp2++ )
			{
				//printNote( "NPC DIALOG: checking '"+_arrNPC_tmp[_iTmp2].GetDescriptionName()+"'" );
				if ( _arrHeroParty.find( _arrNPC_tmp[_iTmp2] ) >= 0  )
					continue;
				else if ( m_Reference.GetWorld().DoesDialogueContainerExist( m_Reference.FindEntityName( _arrNPC_tmp[_iTmp2] )))
				{
					array <string> _arrValidTopics = m_Reference.GetWorld().GetValidTopics( _arrNPC_tmp[_iTmp2].GetDescriptionName() ); 
					array <string> _arrEnabledTopics = m_Reference.GetWorld().GetEnabledTopics( _arrNPC_tmp[_iTmp2].GetDescriptionName() );
					if ( _arrEnabledTopics.length() > 0 )
						_arrNPCsWithDialogs.insertLast( _arrNPC_tmp[_iTmp2] );
					//printNote( "NPC DIALOG: '"+_arrNPC_tmp[_iTmp2].GetDescriptionName()+"', and he/she has '"+_arrEnabledTopics.length()+"' valid topics." );
					//printNote( "TEST: '"+_arrNPC_tmp[_iTmp2].GetDescriptionName()+"' has "+_arrValidTopics.length()+" dialog lines" );
				}
			}
		}
		//printNote( "*** NPC DIALOG: '"+_arrNPCsWithDialogs.length()+"' NPCs with dialogues where found." );
		return _arrNPCsWithDialogs;
	}

	array <Creature> GetCurrentTraders()
	{
		array <Creature> _arrTraders;
		// iterate through all factions
		for ( uint _iTmp1 = 0; _iTmp1 < m_iMaxFactions ; _iTmp1++ )
		{
			array <Creature> _arrCreaturesTmp = m_Reference.FindCreaturesByFaction( _iTmp1, false );
			for ( uint _iTmp2 = 0; _iTmp2 < _arrCreaturesTmp.length() ; _iTmp2++ )
			{
				if ( _arrCreaturesTmp[_iTmp2].IsTrader() )
					_arrTraders.insertLast( _arrCreaturesTmp[_iTmp2] );
			}
		}
		return _arrTraders;
	}*/
	
	// gives back all current enemy-creatures to this faction
	array <Creature> GetEnemies( uint _iFaction )
	{
		array <Creature> _arrEnemies;
		for ( uint _iTmp1 = 0; _iTmp1 < m_iMaxFactions ; _iTmp1++ )
		{
			if ( _iTmp1 != _iFaction && m_Reference.GetFactionRelation( _iFaction, _iTmp1 ) == Hostile )
			{
				array <Creature> _arrCreaturesTmp = m_Reference.FindCreaturesByFaction( _iTmp1, false );
				for ( uint _iTmp2 = 0; _iTmp2 < _arrCreaturesTmp.length() ; _iTmp2++ )
				{
					_arrEnemies.insertLast( _arrCreaturesTmp[_iTmp2] );
					//printNote( "TMP: Description "+_arrCreaturesTmp[_iTmp2].GetDescriptionName()+"; ID "+_arrCreaturesTmp[_iTmp2].GetId() );
				}
			}
		}
		return _arrEnemies;
	}

	// -------------------------------------------------------------------------------------------------------------------
	// --- H E R O   P A R T Y   F U N C T I O N S -----------------------------------------------------------------------

	// this function is needed to quickly give the given sector the wanted resources fro the dictionary
	// possible resources are: 
	// Planks, Brick, Iron, IronBar, BlackAshPackage, BlackAshPotion, Food, LenyaPackage, LenyaEssence, AriaCask, DistilledAria
	
	//Example: RTSRessourcesToSector( "Sector_14", dictionary = {{'Planks', 100}, {'Brick', 50}} );

	void RTSRessourcesToSector ( string _stgSector, dictionary _dictRes )
	{
		// get the main building of the sector
		Building _bldgTmp = m_Reference.GetSectorByName( _stgSector ).GetMainBuilding();
		if ( _bldgTmp.Exists() == false )
			return;

		RTSRessourcesToBuilding( _bldgTmp, _dictRes );
	}

	void RTSRessourcesToBuilding ( Building _bldgTmp, dictionary _dictRes )
	{
		int _iResTmp = 0;
		string _stgPrint = "";

		array <string> _arrKeys = _dictRes.getKeys();

		for ( uint _iTmp = 0; _iTmp < _arrKeys.length(); _iTmp++ )
		{
			_dictRes.get( _arrKeys[_iTmp], _iResTmp);
			if ( _arrKeys[_iTmp] == 'Planks' )
				_bldgTmp.AddResources( Planks, _iResTmp ); 
			else if ( _arrKeys[_iTmp] == 'Food' )
				_bldgTmp.AddResources( Food, _iResTmp ); 
			else if ( _arrKeys[_iTmp] == 'Brick' )
				_bldgTmp.AddResources( Brick, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'Iron' )
				_bldgTmp.AddResources( Iron, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'IronBar' )
				_bldgTmp.AddResources( IronBar, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'BlackAshPackage' )
				_bldgTmp.AddResources( BlackAshPackage, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'BlackAshPotion' )
				_bldgTmp.AddResources( BlackAshPotion, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'LenyaPackage' )
				_bldgTmp.AddResources( LenyaPackage, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'LenyaEssence' )
				_bldgTmp.AddResources( LenyaEssence, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'AriaCask' )
				_bldgTmp.AddResources( AriaCask, _iResTmp );
			else if ( _arrKeys[_iTmp] == 'DistilledAria' )
				_bldgTmp.AddResources( DistilledAria, _iResTmp );
				
			// uncomment this, for test
			//printGameplay("RTS: Player gets "+_iResTmp+" "+ _arrKeys[_iTmp] +".");
		}
	}
	
	void RTSUnlockBlueprints ( array <string> _arrBlueprints )
	{
		for ( uint _iTmp = 0; _iTmp < _arrBlueprints.length();_iTmp++)
			m_Reference.GetWorld().UnlockBlueprint( _arrBlueprints[_iTmp], false );
	}

	void RTSchangeBuildingFactions ( string _Sector, uint _iFaction )
	{
		printNote( "RTS: changing buildings to faction '"+_iFaction+"'" );
		
		array <Building> _arrBuilding = m_Reference.GetSectorByName(_Sector).GetBuildings();
		for( uint _iTmp1 = 0; _iTmp1 < _arrBuilding.length() ; _iTmp1++ )
		{
			if (_arrBuilding[_iTmp1].GetDescriptionName() != "S_Godstone")
				_arrBuilding[_iTmp1].SetFaction(_iFaction);
		}
	}

	void RTSdefeatFaction ( uint _iFaction )
	{
		printNote( "RTS: destroying faction '"+_iFaction+"'" );
		array <Sector@>@ _arrSector = m_Reference.GetSectorsByOwner(_iFaction);
		for( uint _iTmp = 0; _iTmp < _arrSector.length() ; _iTmp++ )
		{
			array <Building> _arrBuilding = _arrSector[_iTmp].GetBuildings();
			for( uint _iTmp1 = 0; _iTmp1 < _arrBuilding.length() ; _iTmp1++ )
			{
				if( _arrBuilding[_iTmp1].GetFaction() == _iFaction )
					_arrBuilding[_iTmp1].Destroy();
			}
		}
		m_Reference.LoseGame( _iFaction );
	}

	// This will turn all Godstones of a specific faction neutral, if the are in sectors not owned by the faction
	void DisableAllGodstonesForFaction( const uint8 _Faction )
	{
		array<Building> _Godstones = {};
		for( uint i = 0; i < m_Reference.FindBuildingsByDescription(_Faction, "S_Godstone").length(); i++ )
			_Godstones.insertLast(m_Reference.FindBuildingsByDescription(_Faction, "S_Godstone")[i]);
		
		for( uint i = 0; i < _Godstones.length(); i++ ) 
		{
			if( _Godstones[i].GetSectorIndex() == uint16(-1) || m_Reference.GetSectorByIndex( _Godstones[i].GetSectorIndex() ).GetOwner() != _Faction )
				_Godstones[i].SetFaction(kFactionNeutral);
		}
	}

	// This will turn all Godstones of a specific faction neutral, ignoring Sectors
	void DisableAllGodstonesForFaction_IgnoreOwnedSectors( const uint8 _Faction )
	{
		array<Building> _Godstones = {};
		for( uint i = 0; i < m_Reference.FindBuildingsByDescription(_Faction, "S_Godstone").length(); i++ )
			_Godstones.insertLast(m_Reference.FindBuildingsByDescription(_Faction, "S_Godstone")[i]);
		
		for( uint i = 0; i < _Godstones.length(); i++ )
			_Godstones[i].SetFaction(kFactionNeutral);
	}

	/*void GodstonesEnable ( bool _bEnable, uint _iInspectionID )
	{
		// m_Reference.AllowGodstoneUse( m_iPlayerFacion, _bEnable)

		array <Building> _arrAllGodstones;
		for ( uint _iTmp = 0; _iTmp <= m_iMaxFactions ; _iTmp++ )
		{
			array <Building> _arrTmp = m_Reference.FindBuildingsByDescription( _iTmp, "S_Godstone" );
			for ( uint _iTmp1 = 0; _iTmp1 < _arrTmp.length() ; _iTmp1++ )
				_arrAllGodstones.insertLast( _arrTmp[_iTmp1] );
		}
		
		for ( uint _iTmp = 0; _iTmp < _arrAllGodstones.length() ; _iTmp++ )
			_arrAllGodstones[_iTmp].SetInspectionText( _iInspectionID );
		
	}*/

	// -------------------------------------------------------------------------------------------------------------------
	// --- M U S I C  F U N C T I O N S ----------------------------------------------------------------------------------

	void PlaySound ( string _stgObject, string _stgSound ) 
	{	
		if ( m_Reference.GetEntitiesByName( _stgObject ).length() > 0 )
			m_Reference.PlaySound(m_iPlayerFaction, uint8(-1), _stgSound, m_Reference.GetEntitiesByName( _stgObject )[0] ); 
		else if ( m_Reference.GetLogicObjectByName( _stgObject ).Exists() )
			m_Reference.PlaySound(m_iPlayerFaction, uint8(-1), _stgSound, m_Reference.GetLogicObjectByName( _stgObject ) ); 
		else 
			printGameplay( " COULDN'T PLAY THE SOUND '"+_stgSound+"' from object position '"+_stgObject+"'" );
	}
	void StopSound ( string _stgObject, string _stgSound ) 
	{
		m_Reference.StopSound(m_iPlayerFaction, uint8(-1), _stgSound, m_Reference.GetEntitiesByName( _stgObject )[0] );
	}

	void PlayTrack ( string _stgTrack ) 
	{
		//printGameplay( "Track: playing '"+_stgTrack+"' " );
		m_Reference.SetGlobalSoundTrack(m_iPlayerFaction, uint8(-1), TrackMusic, _stgTrack );
	}

	void PlayTrack_BackToNormal () { 		PlayTrack(""); }

	void PlayTrack_Silence () { 			PlayTrack("music/silence"); }

	void PlayTrack_FactionsElves_1 () { 	PlayTrack("music/factions/elves_01"); }
	void PlayTrack_FactionsElves_2 () { 	PlayTrack("music/factions/elves_02"); }
	void PlayTrack_FactionsOrcs_1 () { 		PlayTrack("music/factions/orcs_01"); }
	void PlayTrack_FactionsOrcs_2 () { 		PlayTrack("music/factions/orcs_02"); }
	void PlayTrack_FactionsHumans_1 () { 	PlayTrack("music/factions/humans_01"); }
	void PlayTrack_FactionsHumans_2 () { 	PlayTrack("music/factions/humans_02"); }

	void PlaySound_GenericWater ( string _stgObject ) {	m_Reference.PlaySound(m_iPlayerFaction, uint8(-1), "ui/interact_generic_water", m_Reference.GetEntitiesByName( _stgObject )[0] ); }
	void PlaySound_GenericStone ( string _stgObject ) {	m_Reference.PlaySound(m_iPlayerFaction, uint8(-1), "ui/interact_generic_stone", m_Reference.GetEntitiesByName( _stgObject )[0] ); }
	void PlaySound_ItemReceived ( string _stgObject ) {	m_Reference.PlaySound(m_iPlayerFaction, uint8(-1), "ui/quest_item_received", m_Reference.GetEntitiesByName( _stgObject )[0] ); }
	void PlaySound_ItemPaper ( string _stgObject ) {	m_Reference.PlaySound(m_iPlayerFaction, uint8(-1), "ui/quest_item_received", m_Reference.GetEntitiesByName( _stgObject )[0] ); }

	void PlaySoundCoop ( string _stgSound, string _stgObject ) { m_Reference.PlaySound(m_iPlayerFaction, uint8(-1), _stgSound, m_Reference.GetEntitiesByName( _stgObject )[0] ); }


	void PlayTrack_HeroGor () { 			PlayTrack("music/characters/gor"); }
	void PlayTrack_HeroIanna () { 			PlayTrack("music/characters/ianna");}
	void PlayTrack_HeroIanna_combat () { 	PlayTrack("music/characters/sentenza"); }
	void PlayTrack_HeroIsgrimm () { 		PlayTrack("music/characters/isgrimm"); }
	void PlayTrack_HeroRohen () { 			PlayTrack("music/characters/rohen"); }
	void PlayTrack_HeroUndergast () {		PlayTrack("music/characters/undergast"); }
	void PlayTrack_HeroUram () { 			PlayTrack("music/characters/uram"); }
	void PlayTrack_HeroYria () { 			PlayTrack("music/characters/yria"); }

	void PlayTrack_CharSentenza () {		PlayTrack("music/characters/sentenza");	}
	void PlayTrack_CharAngar ()	{			PlayTrack("music/characters/angar");		}
	void PlayTrack_CharRondar_1_short () {	PlayTrack("music/characters/rondar_01_short");	}
	void PlayTrack_CharRondar_1 () {		PlayTrack("music/characters/rondar_01");	}
	void PlayTrack_CharRondar_2 () {		PlayTrack("music/characters/rondar_02");	}
	void PlayTrack_CharRondar_combat () {	PlayTrack("music/characters/rondar_combat"); 	}

	void PlayTrack_CharAndrasSong_1_short () { 	PlayTrack("music/andras_song_01_short"); }
	void PlayTrack_CharAndrasSong_1 () { 	PlayTrack("music/andras_song_01"); }
	void PlayTrack_CharAndrasSong_2 () { 	PlayTrack("music/andras_song_02"); }
	void PlayTrack_CharAndrasSong_3 () { 	PlayTrack("music/andras_song_03"); }

	void PlayTrack_GeneralAfterBattle () {	PlayTrack("music/after_battle");	}
	
	/*void PlayTrack_GeneralBossfight () {	PlayTrack("music/bossfight"); }*/

	
	// --- SETTING AND COMBAT MUSIC 
	// we are using these partly for bosses, or when Basti (Sound Designer)
	// want one of these tracks in a cutscene or situation. 

	void PlaySetting_ashlands ( ) {			PlaySetting_Reset( "ashlands" );			}
	void PlaySetting_ashlands_low ( ) {		PlaySetting_Combat( "ashlands", low );		}
	void PlaySetting_ashlands_med ( ) {		PlaySetting_Combat( "ashlands", med );		}
	void PlaySetting_ashlands_high ( ) {	PlaySetting_Combat( "ashlands", high );		}

	void PlaySetting_desert ( ) {			PlaySetting_Reset( "desert" );				}
	void PlaySetting_desert_low ( ) {		PlaySetting_Combat( "desert", low );		}
	void PlaySetting_desert_med ( ) {		PlaySetting_Combat( "desert", med );		}
	void PlaySetting_desert_high ( ) {		PlaySetting_Combat( "desert", high );		}

	void PlaySetting_grassland ( ) {		PlaySetting_Reset( "grassland" );			}
	void PlaySetting_grassland_low ( ) {	PlaySetting_Combat( "grassland", low );		}
	void PlaySetting_grassland_med ( ) {	PlaySetting_Combat( "grassland", med );		}
	void PlaySetting_grassland_high ( ) {	PlaySetting_Combat( "grassland", high );	}

	void PlaySetting_grasslandNight ( ) {		PlaySetting_Reset( "grassland_night" );			}
	void PlaySetting_grasslandNight_low ( ) {	PlaySetting_Combat( "grassland_night", low );		}
	void PlaySetting_grasslandNight_med ( ) {	PlaySetting_Combat( "grassland_night", med );		}
	void PlaySetting_grasslandNight_high ( ) {	PlaySetting_Combat( "grassland_night", high );	}

	void PlaySetting_jungle ( ) {			PlaySetting_Reset( "jungle" );				}
	void PlaySetting_jungle_low ( ) {		PlaySetting_Combat( "jungle", low );		}
	void PlaySetting_jungle_med ( ) {		PlaySetting_Combat( "jungle", med );		}
	void PlaySetting_jungle_high ( ) {		PlaySetting_Combat( "jungle", high );		}

	void PlaySetting_mountains ( ) {		PlaySetting_Reset( "mountains" );			}
	void PlaySetting_mountains_low ( ) {	PlaySetting_Combat( "mountains", low );		}
	void PlaySetting_mountains_med ( ) {	PlaySetting_Combat( "mountains", med );		}
	void PlaySetting_mountains_high ( ) {	PlaySetting_Combat( "mountains", high );	}

	void PlaySetting_swamp ( ) {			PlaySetting_Reset( "swamp" );				}
	void PlaySetting_swamp_low ( ) {		PlaySetting_Combat( "swamp", low );			}
	void PlaySetting_swamp_med ( ) {		PlaySetting_Combat( "swamp", med );			}
	void PlaySetting_swamp_high ( ) {		PlaySetting_Combat( "swamp", high );		}

	void PlaySetting_dungeon ( ) {			PlaySetting_Reset( "dungeon" );				}

	void PlaySetting_ArchfireForge () { 	PlaySetting( "archfireforge" ); 	}
	void PlaySetting_ArchfireForge_FirstVisit () { PlaySetting( "archfireforge_first_visit" ); 	}

	void PlaySetting_MulandirDef () { 		PlaySetting( "mulandir_defense" ); 	}
	void PlaySetting_MulandirDef_combat () { PlaySetting_Combat( "mulandir_defense", low ); 	}
	void PlaySetting_MulandirDef_heroic () { PlaySetting_Combat( "mulandir_defense", low ); 	}
	void PlaySetting_MulandirDef_danger () { PlaySetting_Combat( "mulandir_defense", low ); 	}


	// sets up everything, that needs to be done for changing the setting and combat musik. 
	void PlaySetting( string _stgSetting )
	{
		m_Reference.SetGlobalSoundTrack( m_iPlayerFaction, uint8(-1), TrackMusic, ("music/setting/"+_stgSetting) );
	}

	void PlaySetting_Combat( string _stgSetting, MusicIntensity _eIntensity )
	{
		m_Reference.SetGlobalSoundTrack( m_iPlayerFaction, uint8(-1), TrackMusic, ("music/setting/"+_stgSetting) );
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "intro", 1 );
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "opener", 0 );
		
		// m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "battle", 10 );

		// handling the intensity
		// ToDo: Setting the intensity hard to a predefined value
		m_Reference.SuspendAutomaticCombatMusic( m_iPlayerFaction, uint8(-1), true );
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "combat", 1 );
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "intensity", _eIntensity );
	}

	// should be called to reset the music back to normal
	void PlaySetting_Reset ( string _stgOriginalSetting )
	{
		m_Reference.SetGlobalSoundTrack( m_iPlayerFaction, uint8(-1), TrackMusic, ("music/setting/"+_stgOriginalSetting) );
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "intro", 1 );
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "opener", 0 );
		
		// ToDo later: "free" the intensity again for a normal calculation
		m_Reference.SuspendAutomaticCombatMusic( m_iPlayerFaction, uint8(-1), false );
		//m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "intensity", 0 );
	}
	void PlaySetting_ResetReset ()
	{
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "intro", 1 );
		m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "opener", 0 );
		
		// ToDo later: "free" the intensity again for a normal calculation
		m_Reference.SuspendAutomaticCombatMusic( m_iPlayerFaction, uint8(-1), false );
		//m_Reference.SetGlobalSoundParameter( m_iPlayerFaction, uint8(-1), "intensity", 0 );
	}

	void PlayTrack_BossBattle( bool _suspendAutomaticCombat = false )
	{
		if( m_b_BossMusicPlaying )
			return;

		if( _suspendAutomaticCombat )
			m_Reference.SuspendAutomaticCombatMusic(m_iPlayerFaction, uint8(-1), true);	

		printNote("Boss Battle Track should play");
		m_Reference.SetGlobalSoundParameter(m_iPlayerFaction, uint8(-1), "bossfight", 1);
		m_Reference.SetGlobalSoundParameter(m_iPlayerFaction, uint8(-1), "combat", 1);
		m_Reference.SetGlobalSoundParameter(m_iPlayerFaction, uint8(-1), "intro", 1);
		m_Reference.SetGlobalSoundParameter(m_iPlayerFaction, uint8(-1), "intensity", 1000);
		m_b_BossMusicPlaying = true;
	}

	void PlayTrack_BackFromBossBattle()
	{
		if( !m_b_BossMusicPlaying )
			return;
		
		printNote("Boss Battle Track should stop");
		m_Reference.SetGlobalSoundParameter(m_iPlayerFaction, uint8(-1), "bossfight", 0);
		m_Reference.SetGlobalSoundParameter(m_iPlayerFaction, uint8(-1), "intro", 0);
		m_Reference.SuspendAutomaticCombatMusic(m_iPlayerFaction, uint8(-1), false);
		m_b_BossMusicPlaying = false;
	}

	// -------------------------------------------------------------------------------------------------------------------
	// --- H E R O   P A R T Y   F U N C T I O N S -----------------------------------------------------------------------

	// Check for Hero Party Death
	bool HeroPartyAnyIsAlive ()
	{
		// Loop through the party
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _arrCrtHeroParty.length(); _iTmp++)
		{
			if(_arrCrtHeroParty[_iTmp].GetCurrentHP () > 0)
				return true;
		}
		// RIP - Seems like all party members are dead...
		return false;
	}
	bool HeroPartyIsAlive ()
	{
		// Loop through the party
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _arrCrtHeroParty.length(); _iTmp++)
		{
			if(_arrCrtHeroParty[_iTmp].GetCurrentHP () == 0)
				return false;
		}
		return true;
	}
	string HeroPartyGetRandomThatIsAlive()
	{
		string _stgRandomHero = "";
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();

		// delete the dead hero's from the party
		uint _iHeroPartyLength = _arrCrtHeroParty.length();
		for ( uint _iTmp1 = 0 ; _iTmp1 < _iHeroPartyLength ; _iTmp1++ )
		{
			if ( _arrCrtHeroParty[_iTmp1].GetCurrentHP() == 0 ) 
			{
				_arrCrtHeroParty.removeAt( _iTmp1 );
				_iHeroPartyLength--;
			}
		}
		if ( _iHeroPartyLength == 0 )
			return _stgRandomHero;
		
		_stgRandomHero = _arrCrtHeroParty[ m_Reference.GetRandom().GetInteger( 0, _arrCrtHeroParty.length()) ].GetDescriptionName();
		return _stgRandomHero;
	}

	// Checks if at least 1 party member is dead
	bool HeroPartyIsMemberDead ()
	{
		// Loop through the party
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _arrCrtHeroParty.length(); _iTmp++)
		{
			if (_arrCrtHeroParty[_iTmp].GetCurrentHP () < 0)
				return true;
		}
		return false;
	}


	void HeroPartySetBusy( bool _bEnable )
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for ( uint _iTmp = 0; _iTmp < _arrCrtHeroParty.length(); _iTmp++ )
			_arrCrtHeroParty[_iTmp].SetBusy(_bEnable);
	}

	void HeroPartyReviveMembers ()
	{
		m_Reference.GetHeroParty( m_iPlayerFaction ).Gather( m_Reference.GetCreatureByName(m_stgAvatar) );
	}
	void HeroPartyReviveMembers_NotCutscene ()
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for ( uint _iTmp = 0; _iTmp < _arrCrtHeroParty.length(); _iTmp++ )
		{
			if ( _arrCrtHeroParty[_iTmp].GetCurrentHP() == 0 )
			{
				//printNote( "Hero is dead: '"+_arrCrtHeroParty[_iTmp].GetDescriptionName()+"'" );
				_arrCrtHeroParty[_iTmp].Revive();
			}
		}
	}

	void HeroPartyStopDialogues()
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for ( uint _iTmp = 0; _iTmp < _arrCrtHeroParty.length(); _iTmp++ )
			_arrCrtHeroParty[_iTmp].CancelDialogue();
	}
	
	// this is transforming Gor to his wolf-form 
	// we have a special condition to transform him to a wolf, so this is simply applying or removing the condition
	
	void HeroPartyGorTransform( bool _bTransform )
	{
		printNote("Try to transform gor's shape");
		if (_bTransform)
			m_Reference.GetCreatureByName(m_stgHero_Gor).ApplyCondition(m_iConditionID_GorWolfForm, -1);
		else 
			m_Reference.GetCreatureByName(m_stgHero_Gor).RemoveCondition(m_iConditionID_GorWolfForm);
	}
	
	// Cutscene version. Only used in cutscenes because cutscenes are stupid and they are unable to send parameters to angle script
	void HeroPartyGorTransformToAnimal()
	{
		m_Reference.GetCreatureByName(m_stgHero_Gor).ApplyCondition(m_iConditionID_GorWolfForm, -1);
	}   
	
	void HeroPartyGorTransformToOrc()
	{
		m_Reference.GetCreatureByName(m_stgHero_Gor).RemoveCondition(m_iConditionID_GorWolfForm);
	}
	
	// teleports the whole hero party to the given position
	// the position should be a LogicObject
	void HeroPartyTeleport( string _stgPos )
	{
		CreatureGroup _crtGrp_HeroParty ( m_Reference );
		_crtGrp_HeroParty.Set(  m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers() );
		_crtGrp_HeroParty.Teleport( m_Reference.GetEntityById( m_Reference.GetLogicObjectByName( _stgPos ).GetId()), false );
	}

	
	// adds the given Creature to the faction and to the hero party of the player
	void HeroPartyJoin ( string _stgCreatureName )
	{
		m_Reference.ShowNotification(m_iPlayerFaction, "HeroJoinedParty", m_Reference.GetCreatureByName(_stgCreatureName)); 

		HeroParty@ _HeroParty = m_Reference.GetHeroParty(m_iPlayerFaction);
		Creature _objCreature = m_Reference.GetCreatureByName( _stgCreatureName );
		_objCreature.SetFaction( m_iPlayerFaction );
		_HeroParty.AddMember( _objCreature );
		_HeroParty.SetHeroOwned( _stgCreatureName, true );
		_objCreature.PreventHeroDespawn( false );

		// call to set him correctly up as the hero party
		//SetHero( _stgCreatureName );

		// check if the hero party is controllable or not 
		// if a new hero is added - also make him not controllable
		if ( !_HeroParty.GetMembers()[0].IsPlayerControllable() )
			_objCreature.SetPlayerControllable( false );
		
		// Check if this Hero was aquired the first time
		if ( m_Reference.GetWorld().GetGlobalBool( (m_glbCat_QuestTrack + "Hero_"+_stgCreatureName), false) == false )
		{
			printNote( "NEW HERO ACQUIRED: "+_stgCreatureName+". Is from now on unlocked." );
			m_Reference.GetWorld().SetGlobalBool( (m_glbCat_QuestTrack + "Hero_"+_stgCreatureName), true);
		}

		// FOR AFFINITY QUEST
		HUB_AffinityQuest_DisableAbility( _stgCreatureName );
	}

	// takes the given hero out of the player hero party, and from his faction
	void HeroPartyLeave ( string _stgCreatureName, int _iFaction )
	{
		m_Reference.ShowNotification(m_iPlayerFaction, "HeroLeftParty", m_Reference.GetCreatureByName(_stgCreatureName)); 

		Creature _objCreature = m_Reference.GetCreatureByName( _stgCreatureName );
		m_Reference.GetHeroParty(m_iPlayerFaction).RemoveMember( _objCreature );
		_objCreature.SetFaction( _iFaction );
		m_Reference.GetHeroParty( _iFaction ).AddMember( _objCreature );

		// if it was a temporary hero, remove him from the owned state
		if ( m_dictRPG_temporaryHeroes.exists( _stgCreatureName ) )
		{
			printNote( "'"+_stgCreatureName+"' leaving the player faction completely." );
			m_Reference.GetHeroParty( _iFaction ).SetHeroOwned( _stgCreatureName, true );
		}
		else 
		{
			printNote( "'"+_stgCreatureName+"' leaving temporarily the hero party, but not the player faction completely." );
			_objCreature.PreventHeroDespawn( true );
		}
	}

	void HeroPartyClearItems ( uint _iFaction )
	{
		array <string> _arrInventoryItems = m_Reference.GetHeroParty( _iFaction ).GetAllItems();
		for ( uint _iTmp2 = 0; _iTmp2 < _arrInventoryItems.length() ; _iTmp2++ )
		{
			uint _iItemNumber = m_Reference.GetHeroParty( _iFaction ).GetItemAmount( _arrInventoryItems[_iTmp2] );
			m_Reference.GetWorld().SetGlobalInt( "GK_Prison__INVENTORY."+_arrInventoryItems[_iTmp2], _iItemNumber );

			m_Reference.GetHeroParty( _iFaction ).RemoveItems( _arrInventoryItems[_iTmp2], _iItemNumber);
		}
	}

	bool HeroPartyCheckIfMember ( string _stgCreatureName, uint _faction )
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty( _faction ).GetMembers();
		for ( uint _iTmp = 0;  _arrCrtHeroParty.length() > _iTmp ; _iTmp++ )
			if ( _arrCrtHeroParty[_iTmp].GetDescriptionName() == _stgCreatureName )
				return true;
		return false;
	}

	void HeroClearEquippment ( string _stgCreatureName, bool _bDestroyOrNot )
	{
		Creature _objCreature = m_Reference.GetCreatureByName( _stgCreatureName );
		if (_bDestroyOrNot)
		{
			_objCreature.Unequip(m_Reference, PrimaryHand, Remove);
			_objCreature.Unequip(m_Reference, SecondaryHand, Remove);
			_objCreature.Unequip(m_Reference, Head, Remove);
			_objCreature.Unequip(m_Reference, Neck, Remove);
			_objCreature.Unequip(m_Reference, Torso, Remove);
			_objCreature.Unequip(m_Reference, Ring1, Remove);
			_objCreature.Unequip(m_Reference, Ring2, Remove);
			_objCreature.Unequip(m_Reference, Holster, Remove);
			_objCreature.Unequip(m_Reference, Item, Remove);
		}
		else 
		{
			_objCreature.Unequip(m_Reference, PrimaryHand, AddToInventory  );
			_objCreature.Unequip(m_Reference, SecondaryHand, AddToInventory  );
			_objCreature.Unequip(m_Reference, Head, AddToInventory  );
			_objCreature.Unequip(m_Reference, Neck, AddToInventory  );
			_objCreature.Unequip(m_Reference, Torso, AddToInventory  );
			_objCreature.Unequip(m_Reference, Ring1, AddToInventory  );
			_objCreature.Unequip(m_Reference, Ring2, AddToInventory  );
			_objCreature.Unequip(m_Reference, Holster, AddToInventory  );
			_objCreature.Unequip(m_Reference, Item, AddToInventory  );
		}
		
	}

	// adds the given hero to party of the given faction
	void HeroPartyJoinFaction ( string _stgCreatureName, int _iFaction )
	{
		HeroParty@ _HeroParty = m_Reference.GetHeroParty(_iFaction);
		Creature _objCreature = m_Reference.GetCreatureByName( _stgCreatureName );
		_objCreature.SetFaction (_iFaction);
		_HeroParty.AddMember ( _objCreature ); 
	}

	// used to make the hero party attackable, or not attackable
	void HeroPartyAttackable( bool _bEnable )
	{
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			_crtHeroes[_iTmp].SetAttackable ( _bEnable );
			_crtHeroes[_iTmp].AllowAttacks( _bEnable );
		}
	}

	// gives the condition for the given time to the whole hero party
	void HeroPartyCastCondition( int _iConditionId, int _iTime )
	{
		m_Reference.GetHeroParty(m_iPlayerFaction).Stop();
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			_crtHeroes[_iTmp].ApplyCondition( _iConditionId, _iTime );
		}
	}
	// takes the given condition away from the hero party
	void HeroPartyClearCondition( int _iConditionId )
	{
		m_Reference.GetHeroParty(m_iPlayerFaction).Stop();
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			_crtHeroes[_iTmp].RemoveCondition( _iConditionId );
		}
	}

	// moves the rest of the heroes to the avatar
	void HeroPartyGatherAtAvatar ()
	{
		printNote( "LevelBase - HeroPartyGatherAtAvatar()" );
		m_Reference.GetHeroParty(m_iPlayerFaction).Stop();
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		Entity _entAvatar = m_Reference.GetEntityById( m_Reference.GetCreatureByName( m_stgAvatar ).GetId() );
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			if ( _crtHeroes[_iTmp].GetDescriptionName() != m_stgAvatar )
				_crtHeroes[_iTmp].GoTo( m_Reference, _entAvatar, 20, 30, true );
		}
	}
	void HeroPartyGatherAtFirst (  )
	{
		m_Reference.GetHeroParty(m_iPlayerFaction).Stop();
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		printNote( "LevelBase - HeroPartyGatherAtFirst(), size of the hero party: '"+_crtHeroes.length()+"'" );
		
		if ( _crtHeroes.length() <= 1 || ( m_Reference.GetCreatureByName( m_stgAvatar ).Exists() && !m_Reference.GetCreatureByName( m_stgAvatar ).IsPlayerControllable()) )
			return; 

		Entity _entGatherAt = m_Reference.GetEntityById( _crtHeroes[0].GetId() );
		string _stgGatherAt = m_Reference.FindEntityName( _entGatherAt );

		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			if ( _crtHeroes[_iTmp].GetDescriptionName() != _stgGatherAt )
				_crtHeroes[_iTmp].GoTo( m_Reference, _entGatherAt, 20, 30, true );
		}
	}

	// moves the rest of the heroes to the avatar
	void HeroPartyGatherAtCreature ( string _stgCrtName )
	{
		printNote( "LevelBase - HeroPartyGatherAtCreature( '"+_stgCrtName+"' )" );
		m_Reference.GetHeroParty(m_iPlayerFaction).Stop();
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		Entity _entCreature = m_Reference.GetEntityById( m_Reference.GetCreatureByName( _stgCrtName ).GetId() );

		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
			_crtHeroes[_iTmp].GoTo( m_Reference, _entCreature, 20, 30, true );
	}

	// moves the rest of the heroes to the avatar
	void HeroPartyLookAt ( string _stgPosition )
	{
		Entity _entTmp;
		if( m_Reference.GetCreatureByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetCreatureByName(_stgPosition).GetId() );
		else if( m_Reference.GetLogicObjectByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetLogicObjectByName(_stgPosition).GetId() );

		// face the position
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
			_crtHeroes[_iTmp].PlayAnimation( m_Reference, Idle, 0, 1000, false, false, _entTmp );

	}

	bool HeroPartyReadyForDialogue()
	{
		array <Creature> _arrParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers();
		for ( uint _iTmp = 0; _iTmp < _arrParty.length() ; _iTmp++ )
			if ( _arrParty[_iTmp].IsInDialogue() || _arrParty[_iTmp].IsBusy() )
				return false;

		if ( m_Reference.IsCampaignFactionInCombat() == false )// && m_Reference.GetCreatureByName(m_stgAvatar).IsBusy() == false )
			return true;

		return false;
	}

	void HeroPartyImmortal ( bool _bEnable )
	{
		m_Reference.GetHeroParty(m_iPlayerFaction).Stop();
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			_crtHeroes[_iTmp].SetImmortal( _bEnable );
		}
	}

	// sets the Hero Party to normal, that means they are not immportal anymore, can be attacked, etc.
	void HeroPartyResetToNormal ()
	{
		HeroPartyAttackable( true );
		HeroPartyImmortal( false );
		PlayerHeroControlEnable();
	}

	// Lets the avatar pick up the object
	// it disabled the given object, and adds the item to the hero inventory
	// there is also the PickUp sound played
	void HeroPickUpObject ( string _stgObject, string _stgItem )
	{
		PlaySound_ItemReceived(_stgObject);
		m_Reference.GetLogicObjectByName( _stgObject ).Enable(false);

		m_Reference.GetHeroParty(m_iPlayerFaction).AddItems(_stgItem, 1);
	}
	void HeroPickUpPaper ( string _stgObject, string _stgItem )
	{
		// is going to be replaced with a paper sound later
		PlaySound_ItemPaper(_stgObject);
		m_Reference.GetLogicObjectByName( _stgObject ).Enable(false);

		m_Reference.GetHeroParty(m_iPlayerFaction).AddItems(_stgItem, 1);
	}

	bool m_bQuestNotificationCurrent = 		false;
	uint m_iNotificationCounter = 			5;
	uint m_iNotificationCounter_counter = 	0;
	void AdvanceInQuestNotification ( string _stgQuest, string _stgTask )
	{
		if( m_bQuestNotificationCurrent )
			return;

		m_bQuestNotificationCurrent = true;
		m_Reference.ShowQuestNotification(m_iPlayerFaction, "QuestTaskRequired", _stgQuest, _stgTask ); 
		m_Reference.SetTimer(TOnTimerEvent(@this.AdvanceQuestNotification_timer), 1);

		//m_Reference.ShowNotification(m_iPlayerFaction, "QuestTaskRequired", m_Reference.GetCreatureByName(m_stgAvatar)); 
	}

	bool AdvanceQuestNotification_timer()
	{
		m_iNotificationCounter_counter++;
		if( m_iNotificationCounter_counter >= m_iNotificationCounter )
		{
			m_iNotificationCounter_counter = 0;
			m_bQuestNotificationCurrent = false;

			return true;
		}

		return false;
	}

	// -------------------------------------------------------------------------------------------------------------------
	
	void AutosaveTimed( uint _iSeconds )
	{
		m_Reference.SetTimer( TOnTimerEvent(@this.Autosave), _iSeconds );
	}
	bool Autosave()
	{
		printImportant( "AUTOSAVE" );
		m_Reference.AutoSave();
		return true;
	}
	bool Autosave_Event_HeroParty ( Creature& in _Creature )
	{
		Autosave();
		return true;
	}

	
	void PlayerHeroControlEnable_Avatar()
	{
		printNote( "Call; PlayerHeroControlEnable_Avatar" );
		PlayerHeroControlDisable();
		m_Reference.GetCreatureByName( m_stgAvatar ).SetPlayerControllable(true);
	}

	// Locks the complete hero party
	// Is mainly used by the writers
	dictionary m_dictDialogueParticipants = { }; // {'Name', dictionary = { {'attackable', false},{'allow_attacks', false},{'immortal', false},{'player_cotrollable', false} } }
	bool m_bCurrentWorldMapSetting = false;
	
	void PlayerHeroControl_Print()
	{
		array <string> _arrKeys = m_dictDialogueParticipants.getKeys();
		for (uint _iTmp = 0; _iTmp < _arrKeys.length(); _iTmp++)
		{
			if( m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).Exists() && m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).GetCurrentHP() > 0 )
			{
				dictionary _dictTmp;
				m_dictDialogueParticipants.get( _arrKeys[_iTmp], _dictTmp );
				
				bool _bAttackable = true;
				bool _bAllow_attacks = true;
				bool _bImmortal = true;
				bool _bPlayer_cotrollable = false;
				_dictTmp.get( 'attackable', _bAttackable );
				_dictTmp.get( 'allow_attacks', _bAllow_attacks );
				_dictTmp.get( 'immortal', _bImmortal );
				_dictTmp.get( 'player_cotrollable', _bPlayer_cotrollable );
				
				printNote( "PLAYER HERO CONTROL: '"+_arrKeys[_iTmp]+"' set to attackable:'"+_bAttackable+"', allow_attacks:'"+_bAllow_attacks+"', immortal:'"+_bImmortal+"', player_cotrollable:'"+_bPlayer_cotrollable+"'" );
			}
		}
	}

	// unlock the hero party again
	void PlayerHeroControlDisable()
	{
		printNote( "Call; PlayerHeroControlDisable" );
		if( !m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers()[0].IsPlayerControllable() )
		{
			printNote( "Call; PlayerHeroControlDisable, Party already locked." );
			return;
		}


		// get participants, if the player is currently in a dialogue
		if ( DialogCheck_GetDialogueCreature() != '' )
		{
			array <Creature>@ _arrParticipants  = m_Reference.GetCreatureByName( DialogCheck_GetDialogueCreature() ).GetDialogueParticipants( m_Reference );
			for (uint _iTmp = 0; _iTmp < _arrParticipants.length(); _iTmp++)
			{
				if( _arrParticipants[_iTmp].Exists() && _arrParticipants[_iTmp].GetCurrentHP() > 0 )
				{
					dictionary _dictTmp = { {'attackable', _arrParticipants[_iTmp].CanBeAttacked()}, {'allow_attacks', _arrParticipants[_iTmp].AreAttacksAllowed()}, {'immortal', _arrParticipants[_iTmp].IsImmortal()}, {'immovable', _arrParticipants[_iTmp].IsImmovable()}, {'player_cotrollable', _arrParticipants[_iTmp].IsPlayerControllable()} };
					m_dictDialogueParticipants.set( m_Reference.FindEntityName(_arrParticipants[_iTmp]), _dictTmp );

					_arrParticipants[_iTmp].SetAttackable( false );
					_arrParticipants[_iTmp].AllowAttacks( false );
					_arrParticipants[_iTmp].SetImmortal( true );
					_arrParticipants[_iTmp].SetImmovable( true );
					_arrParticipants[_iTmp].SetPlayerControllable(false);
				}
			}
			PlayerHeroControl_Print();
		}

		// Handling hero party
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			if( _crtHeroes[_iTmp].GetCurrentHP() != 0 )
			{
				_crtHeroes[_iTmp].SetAttackable( false );
				_crtHeroes[_iTmp].AllowAttacks( false );
				_crtHeroes[_iTmp].SetImmortal( true );
				_crtHeroes[_iTmp].SetImmovable( true );
				_crtHeroes[_iTmp].SetPlayerControllable(false);
			}
		}

		// setting the map accessible state
		m_bCurrentWorldMapSetting = m_Reference.GetWorld().IsMapAccessible(m_iMap_WM);
		EnableWorldMap( false );
	}

	void PlayerHeroControlEnable()
	{
		printNote( "Call; PlayerHeroControlEnable" );
		
		// get participants, if the player is currently in a dialogue
		if( m_dictDialogueParticipants.getKeys().length() != 0)
		{
			PlayerHeroControl_Print();
			array <string> _arrKeys = m_dictDialogueParticipants.getKeys();
			for (uint _iTmp = 0; _iTmp < _arrKeys.length(); _iTmp++)
			{
				if( m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).Exists() && m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).GetCurrentHP() > 0
					&& m_Reference.GetHeroParty(m_iPlayerFaction).IsMember(m_Reference.GetCreatureByName( _arrKeys[_iTmp] )) == false ) 
				{
					dictionary _dictTmp;
					m_dictDialogueParticipants.get( _arrKeys[_iTmp], _dictTmp );
					
					bool _bAttackable = 		true;
					bool _bAllow_attacks = 		true;
					bool _bImmortal = 			true;
					bool _bImmovable = 			true;
					bool _bPlayer_cotrollable = 	false;
					_dictTmp.get( 'attackable', _bAttackable );
					_dictTmp.get( 'allow_attacks', _bAllow_attacks );
					_dictTmp.get( 'immortal', _bImmortal );
					_dictTmp.get( 'immovable', _bImmovable );
					_dictTmp.get( 'player_cotrollable', _bPlayer_cotrollable );
					
					m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).SetAttackable( _bAttackable );
					m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).AllowAttacks( _bAllow_attacks );
					m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).SetImmortal( _bImmortal );
					m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).SetImmovable( _bImmovable );
					m_Reference.GetCreatureByName( _arrKeys[_iTmp] ).SetPlayerControllable( _bPlayer_cotrollable );
				}
				m_dictDialogueParticipants.delete( _arrKeys[_iTmp]);
			}
		}

		// Handling hero party
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			if( _crtHeroes[_iTmp].GetCurrentHP() != 0 )
			{
				_crtHeroes[_iTmp].SetAttackable( true );
				_crtHeroes[_iTmp].AllowAttacks( true );
				_crtHeroes[_iTmp].SetImmortal( false );
				_crtHeroes[_iTmp].SetPlayerControllable(true);
			}
		}

		// setting the map accessible state
		EnableWorldMap( m_bCurrentWorldMapSetting );
	}

	/*void PlayerHeroControlEnable_Interrupted()
	{
		// get topic and who is in dialogue
		array <string> _crtCreaturesInDialogue = m_dictCurrentShoutoutsHappening.getKeys();
		for( uint _iTmp = 0 ; _iTmp < _crtCreaturesInDialogue.length() ; _iTmp++ )
		{
			array <Creature> _arrCrt = m_Reference.GetCreatureByName(_crtCreaturesInDialogue[_iTmp]).GetDialogueParticipants( m_Reference );
			if( _arrCrt.find( m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers()[0]) != -1)
			{
				string _stgTopic = "";
				m_dictCurrentShoutoutsHappening.get( _crtCreaturesInDialogue[_iTmp],_stgTopic  );
				printNote( "HOLY SHIT!!!!! I found the dialogue, where the hero party is in o.o - Creature '"+_crtCreaturesInDialogue[_iTmp]+"' and Topic: '"+_stgTopic+"'" );
				m_Reference.GetWorld().EnableDialogueTopic( _crtCreaturesInDialogue[_iTmp], _stgTopic, true );
				PlayerHeroControlEnable();
			}
		}
		//if( _crtCreaturesInDialogue.length() > 0 )


		/*dictionary _dictTmp =  (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = {{'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, 
			{'not_in_dialogue', _bCheckDialogues}, {'combat', _bCheckCombat}, {'gathered', _bCheckGathered}, {'alive_HeroParty', _bCheckPartyAlive}, {'stop_party', _bStopHeroParty}, {'reveal_speaker', _bRevealSpeaker}, {'queued', _bQueued}, {'seconds', timer} } 
		);

		// and now enable
	}*/


	// -------------------------------------------------------------------------------------------------------------------
	// --- M A R K E R   F U N C T I O N S -------------------------------------------------------------------------------

	/* 	ONLY use this function, if the Writer/Content designers are especially asking for this. 
		Most of the markers are done automatically, and we should only carefully use scripted markers, as they can mess with the generall system.
			string _stgMarkerPositionName
				name of the position, where the marker should be shown
			string _stgMarkerFunction
				name of the kind of marker. There is a wide range, but choose carefully which one you want to use in which situation
					"BaseUnderAttack" "BouldersCleared" 
					"BuildingCharged" "BuildingCompleted" "BuildingInactive" "BuildingMarkedForDestruction" 
					"BuildingNoWorkers" "BuildingRepairActive" "BuildingResourcesMissing"
					"BuildingStorageFull" "BuildingSuspended" "BuildingUpgradeCompleted"
					"DialogueAvailable" "HeroDied" "HeroPartyGather" "HoldPosition" "ItemReceived" "LevelUp" 
					"NoFreeWorkers" "PlayerDefeated"
					"POIMarker" "QuestMarkerRevealed" "ResearchCompleted" "ResourcesDepletedPerBuilding" 
					"ResourcesDepletedSectorWide" "RetreatActive" "SectorConquered" "SectorLost" 
					"SettlerCarriageCreated" "UnderAttack"
			string _stgNotificationState
				we differentiate between three kind of notification states:
					"Show" "Activate" "Deactivate"
			int iFaction
				simply the faction, for which it should be displayed
	*/
	// This function is used for markers on entities, like creatures and so on
	void MarkerEntity ( string _stgMarkerPositionName, string _stgMarkerFunction, string _stgNotificationState, int _iFaction )
	{
		// first check, if there are entities with the marker name
		array <Entity>@ _entMarker = m_Reference.GetEntitiesByName( _stgMarkerPositionName ); 
		for (uint _iTmp = 0; _iTmp < _entMarker.length(); _iTmp++)
		{
			if (_stgNotificationState == "Show")
				m_Reference.ShowNotification( _iFaction, _stgMarkerFunction, _entMarker[_iTmp] );
			else if (_stgNotificationState == "Activate")
				m_Reference.BeginNotification( _iFaction, _stgMarkerFunction, _entMarker[_iTmp] );
			else if (_stgNotificationState == "Deactivate")
				m_Reference.EndNotification( _iFaction, _stgMarkerFunction, _entMarker[_iTmp] );
		}
	}
	// This function is used on logic objects, and can also reveal the area around it
	void MarkerLogic ( string _stgMarkerPositionName, string _stgMarkerFunction, string _stgNotificationState, bool _bShowArea, int _iFaction )
	{
		// and now, we check, if there are Logic Objects named after it
		LogicObject _lgMarker = m_Reference.GetLogicObjectByName( _stgMarkerPositionName );
		if (_bShowArea)
		{
			_lgMarker.SetFaction(_iFaction);
			_lgMarker.SetSightRange(m_iMarkerSightRange);
			_lgMarker.Enable(true);
		}
		
		if (_stgNotificationState == "Show")
			m_Reference.ShowNotification( _iFaction, _stgMarkerFunction, _lgMarker );
		else if (_stgNotificationState == "Activate")
			m_Reference.BeginNotification( _iFaction, _stgMarkerFunction, _lgMarker );
		else if (_stgNotificationState == "Deactivate")
			m_Reference.EndNotification( _iFaction, _stgMarkerFunction, _lgMarker );
	}
	
	// Function to activate or deactivate a dialogue bubble on a creature
	// be careful to use it, most of the time the writers can do these via Articy
	// only use this, when the writers asks for it
	void MarkerDialogueForCreatures ( string _stgDescription, bool _bEnable, int _iFaction )
	{	
		array <Creature> _arrCrt_Tmp = m_Reference.FindCreaturesByDescription( _iFaction, _stgDescription );

		m_Reference.BeginNotification( m_iPlayerFaction, "DialogueAvailable", _arrCrt_Tmp[0] );
		if (_arrCrt_Tmp.length == 0)
			return;

		for ( uint _iTmp = 0; _iTmp < _arrCrt_Tmp.length() ; _iTmp++ )
		{
			//printNote("AHSJDK " + _arrCrt_Tmp[_iTmp].GetDescriptionName() + " - " +_bEnable );
			if ( _bEnable == true )
				m_Reference.BeginNotification( m_iPlayerFaction, "DialogueAvailable", _arrCrt_Tmp[_iTmp] );
			else if ( _bEnable == false )
				m_Reference.EndNotification( m_iPlayerFaction, "DialogueAvailable", _arrCrt_Tmp[_iTmp] );
		}
	}
	
	void Banner_Humans ( int _iID )
	{
		printNote("Playing the location banner of the humans");
		m_Reference.ShowExplorationBanner( m_iPlayerFaction, _iID, "banner_location", 500, 5000, 500, "ui/exploration_banner" );
	}

	// -------------------------------------------------------------------------------------------------------------------
	// --- C R E A T U R E S   F U N C T I O N S -------------------------------------------------------------------------

	void StartTrading( string _stgCreature )
	{
		printNote( _stgCreature+"; Starting trade with the Avatar.");
		//m_Reference.GetCreatureByName( _stgCreature ).Trade( m_Reference, m_Reference.GetCreatureByName( m_stgAvatar ), false, m_iPlayerFaction, 0 );
		m_Reference.GetCreatureByName( m_stgAvatar ).Trade( m_Reference, m_Reference.GetCreatureByName( _stgCreature ), false, m_iPlayerFaction, 0 );
	}

	// uneqipps the whole hero party
	// the equippment is moved to the inventory
	void HeroPartyUnequip()
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers();
		for ( uint _iTmp = 0;  _arrCrtHeroParty.length() > _iTmp ; _iTmp++ )
			_arrCrtHeroParty[_iTmp].HideWeapons( true );
	}
	// eqipps the hero party again
	// takes the items, that where uneqiped and that are in the inventory
	void HeroPartyReequip()
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers();
		for ( uint _iTmp = 0;  _arrCrtHeroParty.length() > _iTmp ; _iTmp++ )
			_arrCrtHeroParty[_iTmp].HideWeapons( false );
	}

	// uneqipps the whole hero party
	// the equippment is moved to the inventory
	void HeroPartyUnequip_NotCutscene()
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers();
		for ( uint _iTmp = 0;  _arrCrtHeroParty.length() > _iTmp ; _iTmp++ )
			CreatureUnequipWeapons(_arrCrtHeroParty[_iTmp].GetDescriptionName());
	}
	// eqipps the hero party again
	// takes the items, that where uneqiped and that are in the inventory
	void HeroPartyReequip_NotCutscene()
	{
		array <Creature>@ _arrCrtHeroParty = m_Reference.GetHeroParty(m_iPlayerFaction).GetMembers();
		for ( uint _iTmp = 0;  _arrCrtHeroParty.length() > _iTmp ; _iTmp++ )
			CreatureEquipWeapons(_arrCrtHeroParty[_iTmp].GetDescriptionName());
	}


	void CreatureLookAt( string _stgCreature, string _stgPosition )
	{
		Entity _entTmp;
		if( m_Reference.GetCreatureByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetCreatureByName(_stgPosition).GetId() );
		else if( m_Reference.GetLogicObjectByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetLogicObjectByName(_stgPosition).GetId() );

		// face the position
		m_Reference.GetCreatureByName( _stgCreature ).PlayAnimation( m_Reference, Idle, 0, 1000, false, false, _entTmp );
	}

	void CreatureUnequipWeapons ( string _stgCreature )
	{
		printGameplay( "Unequipping Hero/NPC '"+_stgCreature+"'" );
		Creature _crtTmp = m_Reference.GetCreatureByName( _stgCreature );
		string _stgTmp = "";
		bool _bTmp = false;

		// Get and save the information about the PrimaryHand
		_bTmp = _crtTmp.GetEquipment(PrimaryHand, _stgTmp);
		if (_bTmp)
			m_Reference.GetWorld().SetGlobalInt( m_glbCat_SaveEquipment_Weapons+"__"+_stgCreature+".PrimaryHand"+"//"+_stgTmp, 1 );
		
		// and now from the Secondary Hand
		_bTmp = _crtTmp.GetEquipment(SecondaryHand, _stgTmp);
		if (_bTmp)
			m_Reference.GetWorld().SetGlobalInt( m_glbCat_SaveEquipment_Weapons+"__"+_stgCreature+".SecondaryHand"+"//"+_stgTmp, 1 );
		
		// Unequiping the creature
		_crtTmp.Unequip( m_Reference, PrimaryHand, AddToInventory, 1 );
		_crtTmp.Unequip( m_Reference, SecondaryHand, AddToInventory, 1 );
	}

	void CreatureEquipWeapons ( string _stgCreature )
	{
		printGameplay( "Reequipping Hero/NPC '"+_stgCreature+"'" );

		dictionary _dictEquipment = m_Reference.GetWorld().GetGlobalVarsInCategory( m_glbCat_SaveEquipment_Weapons+"__"+_stgCreature, false );
		if( _dictEquipment.isEmpty() )
		{
			printGameplay( " - Doesn't have anything saved, so there is nothing to reequipp here." );
			return; 
		}

		array <string> _stgKeys = _dictEquipment.getKeys();
		for ( uint _iTmp_2 = 0; _iTmp_2 < _stgKeys.length() ; _iTmp_2++ )
		{
			string _stgItemName = _stgKeys[_iTmp_2];
			string _stgItemSlot = _stgKeys[_iTmp_2];
			_stgItemName = _stgItemName.substr( (_stgItemName.findFirst("//", 0)+2), -1);
			_stgItemSlot = _stgItemSlot.substr( 0, _stgItemSlot.findFirst("//", 0) );

			EItemSlot _enumItemSlot = None;
			if ( _stgItemSlot == 'PrimaryHand' )
				_enumItemSlot = PrimaryHand;
			else if ( _stgItemSlot == 'SecondaryHand' )
				_enumItemSlot = SecondaryHand;
			else 
				continue;

			m_Reference.GetCreatureByName( _stgCreature ).Equip( m_Reference, _enumItemSlot, _stgItemName, FromInventory ); 
		}

		// clearing the category
		m_Reference.GetWorld().ClearGlobalVarCategory( m_glbCat_SaveEquipment_Weapons+"__"+_stgCreature );
	}

	dictionary CreatureGetEquipedItems ( string _stgCreature )
	{
		Creature _crtCreature = m_Reference.GetCreatureByName( _stgCreature );
		dictionary _dictEquipment = {{'PrimaryHand', ''}, {'SecondaryHand', ''}, {'Head', ''}, {'Neck', ''}, {'Torso', ''}, {'Ring1', ''}, {'Ring2', ''}, {'Item', ''} };
		array <string> _arrKeys = _dictEquipment.getKeys();

		for ( uint _iTmp = 0 ; _iTmp < _arrKeys.length(); _iTmp++ )
		{	
			string _stgItemName = "";
			EItemSlot _enumItemSlot = None;

			if ( _arrKeys[_iTmp] == 'PrimaryHand' )
				_enumItemSlot = PrimaryHand;
			else if ( _arrKeys[_iTmp] == 'SecondaryHand' )
				_enumItemSlot = SecondaryHand;
			else if ( _arrKeys[_iTmp] == 'Head' )
				_enumItemSlot = Head;
			else if ( _arrKeys[_iTmp] == 'Neck' )
				_enumItemSlot = Neck;
			else if ( _arrKeys[_iTmp] == 'Torso' )
				_enumItemSlot = Torso;
			else if ( _arrKeys[_iTmp] == 'Ring1' )
				_enumItemSlot = Ring1;
			else if ( _arrKeys[_iTmp] == 'Ring2' )
				_enumItemSlot = Ring2;
			else if ( _arrKeys[_iTmp] == 'Holster' )
				_enumItemSlot = Holster;
			else if ( _arrKeys[_iTmp] == 'Item' )
				_enumItemSlot = Item;
			else 
				continue;

			_crtCreature.GetEquipment( _enumItemSlot, _stgItemName);
			_dictEquipment.set( _arrKeys[_iTmp], _stgItemName );
		}

		return _dictEquipment;
	}

	void CreatureUnequip ( string _stgCreature, ECreatureUnequipMode _enumUnequipMode )
	{
		Creature _crtCreature = m_Reference.GetCreatureByName( _stgCreature );
		dictionary _dictEquipment = {{'PrimaryHand', ''}, {'SecondaryHand', ''}, {'Head', ''}, {'Neck', ''}, {'Torso', ''}, {'Ring1', ''}, {'Ring2', ''}, {'Item', ''} };
		array <string> _arrKeys = _dictEquipment.getKeys();

		for ( uint _iTmp = 0 ; _iTmp < _arrKeys.length(); _iTmp++ )
		{	
			EItemSlot _enumItemSlot = None;
			string _stgItemName; 

			if ( _arrKeys[_iTmp] == 'PrimaryHand' )
				_enumItemSlot = PrimaryHand;
			else if ( _arrKeys[_iTmp] == 'SecondaryHand' )
				_enumItemSlot = SecondaryHand;
			else if ( _arrKeys[_iTmp] == 'Head' )
				_enumItemSlot = Head;
			else if ( _arrKeys[_iTmp] == 'Neck' )
				_enumItemSlot = Neck;
			else if ( _arrKeys[_iTmp] == 'Torso' )
				_enumItemSlot = Torso;
			else if ( _arrKeys[_iTmp] == 'Ring1' )
				_enumItemSlot = Ring1;
			else if ( _arrKeys[_iTmp] == 'Ring2' )
				_enumItemSlot = Ring2;
			else if ( _arrKeys[_iTmp] == 'Holster' )
				_enumItemSlot = Holster;
			else if ( _arrKeys[_iTmp] == 'Item' )
				_enumItemSlot = Item;
			else 
				continue;

			_crtCreature.GetEquipment( _enumItemSlot, _stgItemName);

			// save to global variables
			m_Reference.GetWorld().SetGlobalInt( m_glbCat_SaveEquipment_Weapons+"__"+_stgCreature+"."+_arrKeys[_iTmp]+"//"+_stgItemName, 1 );
			_crtCreature.Unequip (m_Reference, _enumItemSlot, _enumUnequipMode, 1 );
		}
	}
	void CreatureReequip ( string _stgCreature, ECreatureEquipMode _enumUnequipMode )
	{
		Creature _crtCreature = m_Reference.GetCreatureByName( _stgCreature );
		dictionary _dictEquipment = m_Reference.GetWorld().GetGlobalVarsInCategory( m_glbCat_SaveEquipment_Weapons+"__"+_stgCreature, false );
		if( _dictEquipment.isEmpty() )
		{
			printGameplay( " - Doesn't have anything saved, so there is nothing to reequipp here." );
			return; 
		}

		array <string> _arrKeys = _dictEquipment.getKeys();
		for ( uint _iTmp_2 = 0; _iTmp_2 < _arrKeys.length() ; _iTmp_2++ )
		{
			string _stgItemName = _arrKeys[_iTmp_2];
			string _stgItemSlot = _arrKeys[_iTmp_2];
			_stgItemName = _stgItemName.substr( (_stgItemName.findFirst("//", 0)+2), -1);
			_stgItemSlot = _stgItemSlot.substr( 0, _stgItemSlot.findFirst("//", 0) );
			EItemSlot _enumItemSlot = None;

			if ( _stgItemSlot == 'PrimaryHand' )
				_enumItemSlot = PrimaryHand;
			else if ( _stgItemSlot == 'SecondaryHand' )
				_enumItemSlot = SecondaryHand;
			else if ( _stgItemSlot == 'Head' )
				_enumItemSlot = Head;
			else if ( _stgItemSlot == 'Neck' )
				_enumItemSlot = Neck;
			else if ( _stgItemSlot == 'Torso' )
				_enumItemSlot = Torso;
			else if ( _stgItemSlot == 'Ring1' )
				_enumItemSlot = Ring1;
			else if ( _stgItemSlot == 'Ring2' )
				_enumItemSlot = Ring2;
			else if ( _stgItemSlot == 'Holster' )
				_enumItemSlot = Holster;
			else if ( _stgItemSlot == 'Item' )
				_enumItemSlot = Item;
			
			if( _stgItemName != '' && _enumItemSlot != -1 )
				m_Reference.GetCreatureByName( _stgCreature ).Equip( m_Reference, _enumItemSlot, _stgItemName, FromInventory ); 

			//printNote( " - REEQUIPPING "+_arrKeys[_iTmp_2]+" '"+_stgItemSlot+"' ("+_enumItemSlot+") '"+_stgItemName+"'" );
		}

		// clearing the category
		m_Reference.GetWorld().ClearGlobalVarCategory( m_glbCat_SaveEquipment_Weapons+"__"+_stgCreature );
	}

	void CreatureReveal ( string _stgCreature )
	{
		m_Reference.GetCreatureByName( _stgCreature ).ApplyCondition( m_iRevealCondition, m_iRevealTime, m_iPlayerFaction );
	}

	void RevealArea ( string _stgArea, uint _iSeconds )
	{
		m_Reference.AddVisiblePath( m_iPlayerFaction, _stgArea );
		m_Reference.SetTimer( TOnTimerUserDataEvent(@this.RevealArea_timer), _iSeconds, _stgArea );
	}
	bool RevealArea_timer ( const string& in _stgKey )
	{
		m_Reference.RemoveVisiblePath( m_iPlayerFaction, _stgKey );
		return true;
	}

	/*void CreatureCastSpecialSpell ( string _stgCreature, string _stgSpellname, string _stgTarget, bool _bTargetLogicObject )
	{
		printNote( _stgCreature+" is casting " + _stgSpellname + " at the target " +_stgTarget +"("+_bTargetLogicObject+")" );
		Creature _crtTmp = m_Reference.GetCreatureByName( _stgCreature );
		_crtTmp.AddSpell( m_Reference, _stgSpellname);

		if ( _bTargetLogicObject )
			_crtTmp.Cast( m_Reference, _stgSpellname, m_Reference.GetLogicObjectByName( _stgTarget ), false);
		else 
			_crtTmp.Cast( m_Reference, _stgSpellname, m_Reference.GetCreatureByName( _stgTarget ), false);

		_crtTmp.RemoveSpell( m_Reference, _stgSpellname);
	}*/

	array <Creature> GetCreaturesFromSpawns( array <string> _arrSpawns )
	{
		array <Creature> _arrCreatures; 

		// get a whole array with all the utran villagers
		for ( uint _iTmp = 0; _iTmp < _arrSpawns.length(); _iTmp++ )
		{
			array <Creature> _arrCrt = m_Reference.GetCreaturesFromSpawn( _arrSpawns[_iTmp] ); 
			for ( uint _iTmp2 = 0; _iTmp2 < _arrCrt.length(); _iTmp2++ )
				_arrCreatures.insertLast( _arrCrt[_iTmp2] );
		}
		return _arrCreatures;
	}
	array <string> GetCreaturesFromSpawns_stg( array <string> _arrSpawns )
	{
		array <string> _arrCreatures; 

		// get a whole array with all the utran villagers
		for ( uint _iTmp = 0; _iTmp < _arrSpawns.length(); _iTmp++ )
		{
			array <Creature> _arrCrt = m_Reference.GetCreaturesFromSpawn( _arrSpawns[_iTmp] ); 
			for ( uint _iTmp2 = 0; _iTmp2 < _arrCrt.length(); _iTmp2++ )
				_arrCreatures.insertLast( m_Reference.FindEntityName( _arrCrt[_iTmp2] ) );
		}
		return _arrCreatures;
	}

	void EnablePOIVisitingBehaviorSpawn ( string _stgSpawn, bool _bEnable )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
			_arrCrtTmp[_iTmp].EnablePOIVisitingBehavior ( _bEnable );
	}
	void EnablePOIVisitingBehaviorSpawns ( array <string> _stgSpawns, bool _bEnable )
	{
		for ( uint _iTmp = 0 ; _iTmp < _stgSpawns.length(); _iTmp++ )
			EnablePOIVisitingBehaviorSpawn( _stgSpawns[_iTmp], _bEnable );
	}

	void SetPOICategoriesSpawn ( string _stgSpawn, string[] _CategoryNames )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
			_arrCrtTmp[_iTmp].SetPOICategories(m_Reference, _CategoryNames);
	}
	void SetPOICategoriesSpawns ( string[] _arrSpawns, string[] _CategoryNames )
	{
		array <Creature> _arrCrtTmp = GetCreaturesFromSpawns( _arrSpawns );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
			_arrCrtTmp[_iTmp].SetPOICategories(m_Reference, _CategoryNames);
	}

	void SetSpawnImmovable ( string _stgSpawn, bool _bTrueFalse )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
			_arrCrtTmp[_iTmp].SetImmovable(_bTrueFalse);
	}
	void SetSpawnImmortal ( string _stgSpawn, bool _bTrueFalse )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
			_arrCrtTmp[_iTmp].SetImmortal(_bTrueFalse);
	}
	void SetSpawnNotAttackable ( string _stgSpawn, bool _bTrueFalse )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
		{
			_arrCrtTmp[_iTmp].AllowAttacks(_bTrueFalse);
			_arrCrtTmp[_iTmp].SetAttackable(_bTrueFalse);
		}
	}

	void SetFactionSpawn ( string _stgSpawn, int _iFaction )
	{
		array <Creature>@ _arrCrtTmp = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
		for ( uint _iTmp = 0; _iTmp < _arrCrtTmp.length() ; _iTmp++ )
			_arrCrtTmp[_iTmp].SetFaction(_iFaction);
	}

	void SetFactionSpawns ( array <string> _arrSpawns, int _iFaction )
	{
		for ( uint _iTmp = 0; _iTmp < _arrSpawns.length() ; _iTmp++)
			SetFactionSpawn( _arrSpawns[_iTmp], _iFaction );
	}


	// -------------------------------------------------------------------------------------------------------------------
	// --- C R E A T U R E S   F U N C T I O N S -------------------------------------------------------------------------
	
	void EnemyAI ( uint _iFaction, bool _bEnable )
	{
		printNote("Faction "+_iFaction+", AI is going to be changed to: "+_bEnable );

		m_Reference.SetAIFlag( _iFaction, CanControlUnits, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanControlBuildings, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanControlProduction, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanAttack, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanScout, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanExpand, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanDefend, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanLoot, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanManageEquipment, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanAssignAttributes, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanAssignSkills, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanBuild, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanUpgradeBuildings, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanManageWorkers, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanProduceUnits, _bEnable );
		m_Reference.SetAIFlag( _iFaction, CanUpgradeUnits, _bEnable );
	}

	void EnemyAI_Start ( uint _iFaction )
	{
		m_Reference.ActivateAI( _iFaction );
		printNote("Faction " + _iFaction + ", AI activated.");
	}


	// -------------------------------------------------------------------------------------------------------------------
	// --- T R A N S F E R   F E A T U R E -------------------------------------------------------------------------------

	/*
		This functions is used to transfer a set of creatures on Map A to a later Map B
		
		_stgGlobalCategory: the global category of variables, where the number and type of creatures are saved
		_arrStgSpawns: an array of the spawns, which contain the new creatures that should be synchronized
	*/ 
	void SynchronizeGlobalAndSpawns ( string _stgGlobalCategory, array <string> _arrStgSpawns )
	{	
		string _stgTmp = "[SCRIPT] - NOTE: SYNCHRONIZING, global variables "+_stgGlobalCategory+" with the spawns ";
		for ( uint _iSpawns = 0; _iSpawns < _arrStgSpawns.length() ; _iSpawns++ )
			_stgTmp = _stgTmp + ", " + _arrStgSpawns[_iSpawns];
		print(_stgTmp + ".");

		if ( m_Reference.GetWorld().GetGlobalVarNamesInCategory(_stgGlobalCategory, true).length() == 0 )
		{
			printNote("SYNCHRONIZING: depawning all");
			for ( uint _iSpawns = 0; _iSpawns < _arrStgSpawns.length() ; _iSpawns++ )
				SpawnDespawn( _arrStgSpawns[_iSpawns] );
		}
		else 
		{
			printNote("SYNCHRONIZING: Some Militia was saved");
			for ( uint _iSpawns = 0; _iSpawns < _arrStgSpawns.length() ; _iSpawns++ )
			{
				string _stgSpawn = _arrStgSpawns[_iSpawns];

				array <Creature>@ _arrCrt_1 = m_Reference.GetCreaturesFromSpawn( _stgSpawn );
				for ( uint _iTmp1 = 0; _iTmp1 < _arrCrt_1.length() ; _iTmp1++ )
				{
					string _stgGlobal_UnitType = _stgGlobalCategory+"." + _arrCrt_1[_iTmp1].GetDescriptionName();
					if (m_Reference.GetWorld().GetGlobalInt(_stgGlobal_UnitType) > 0 )
						m_Reference.GetWorld().SetGlobalInt(_stgGlobal_UnitType, (m_Reference.GetWorld().GetGlobalInt(_stgGlobal_UnitType) - 1) );
					else 
					{
						_arrCrt_1[_iTmp1].Enable(false);
						_arrCrt_1[_iTmp1].Kill();
					}
				}
			}
			
			// Clearing this category, to keep it simple and clean
			m_Reference.GetWorld().ClearGlobalVarCategory( _stgGlobalCategory );
		}
	}

	
	// -------------------------------------------------------------------------------------------------------------------
	// --- W E A T H E R  F U N C T I O N S  -----------------------------------------------------------------------------

	void Weather_sunshine() { 			m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'sunshine' ) "); }
	void Weather_sunshineFoggy() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'sunshineFoggy' ) "); }

	void Weather_overcastLight() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'overcastLight' ) "); }
	void Weather_overcast() { 			m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'overcast' ) "); }
	void Weather_overcastHeavy() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'overcastHeavy' ) "); }
	void Weather_overcastThunder() { 	m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'overcastThunder' ) "); }
	
	void Weather_overcastRainLight() { 	m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'overcastRainLight' ) "); }
	void Weather_overcastStormyLight() {m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'overcastStormyLight' ) "); }
	
	void Weather_cloudyLight() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyLight' ) "); }
	void Weather_cloudyLightFoggy() { 	m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyLightFoggy' ) "); }
	void Weather_cloudyLightWindy() { 	m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyLightWindy' ) "); }
	
	void Weather_cloudy() {				m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudy' ) "); }
	void Weather_cloudyFoggy() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyFoggy' ) "); }
	void Weather_cloudyWindy() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyWindy' ) "); }
	
	void Weather_cloudyHeavy() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyHeavy' ) "); }
	void Weather_cloudyHeavyFoggy() { 	m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyHeavyFoggy' ) "); }
	void Weather_cloudyHeavyWindy() { 	m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'cloudyHeavyWindy' ) "); }

	void Weather_rainLight() { 			m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'rainLight' ) "); }
	void Weather_rain() { 				m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'rain' ) "); }
	void Weather_rainHeavy() { 			m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'rainHeavy' ) "); }
	
	void Weather_stormLight() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'stormLight' ) "); }
	void Weather_storm() { 				m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'storm' ) "); }
	void Weather_stormHeavy() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'stormHeavy' ) "); }

	void Weather_interior() { 			m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'interior' ) "); }
	void Weather_interiorFoggyLight() { m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'interiorFoggyLight' ) "); }
	void Weather_interiorFoggy() { 		m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'interiorFoggy' ) "); }
	void Weather_interiorFoggyHeavy() { m_Reference.CallWeatherScript( "Script.SetWeatherProfile ( 'interiorFoggyHeavy' ) "); }

	
// -------------------------------------------------------------------------------------------------------------------
// --- D I A L O G U E   F U N C T I O N S ---------------------------------------------------------------------------

	// -------------------------------------------------------------------------------------------------- BASIC EVENTS
	

	// Dialogue and shoutout configuration
	uint m_iDiaWait_BanternReady = 			6;
	uint m_iDiaWait_GenerallyReady = 		4;
	uint m_iDiaWait_SpecialReady = 			3;
	uint m_iDiaWait_BanternReady_wait = 	0;
	uint m_iDiaWait_GenerallyReady_wait = 	0;
	uint m_iDiaWait_SpecialReady_wait = 	0;
	
	uint m_iDiaWait_Shoutout = 				2;
	uint m_iDiaWait_ShoutoutLong = 			5;

	// used to count, until it is time for these here
	
	uint m_iDiaDis_TalkDistance_Avatar = 	20;
	uint m_iDiaDis_TalkDistance = 			30;

	bool m_bDialogueBlocked = 				false;
	bool m_bDia_tickerEnabled = 			false;
	
	uint m_iWaitForNextDialogue = 		2;

	dictionary m_dictDialogueQueues = 
	{
		{'GenerallyReady', 	dictionary = {} },
		{'Gathered', 		dictionary = {} }, 
		{'Shoutout', 		dictionary = {} },
		{'Alive_FullParty', dictionary = {} },
		{'Combat', 			dictionary = {} }, 
		{'Timed', 			dictionary = {} },

		{'Bantern', 		dictionary = {} }
	};
	dictionary m_dictCurrentShoutoutsHappening = { };

	// {'not_in_dialogue', _bCheckDialogues}, {'combat', _bCheckCombat}, {'gathered', _bCheckGathered}, {'alive_HeroParty', _bCheckPartyAlive}, {'stop_party', _bStopHeroParty}, {'reveal_speaker', _bRevealSpeaker}, {'queued', _bQueued}, {'seconds', timer} } 
	void printDialogDictionary( dictionary _dictTmp )
	{
		array <string> _arrKeys = _dictTmp.getKeys();
		for( uint _iTmp = 0; _iTmp < _arrKeys.length() ; _iTmp++ )
		{
			if( _arrKeys[_iTmp] == 'seconds' )
			{
				uint _iTimer = 0;
				_dictTmp.get( _arrKeys[_iTmp], _iTimer );
				printDialog( "  - '"+_arrKeys[_iTmp]+"'; '"+_iTimer+"'" );
			}
			else if ( _arrKeys[_iTmp] == 'stop_party' || _arrKeys[_iTmp] == 'not_in_dialogue' || _arrKeys[_iTmp] == 'combat' || _arrKeys[_iTmp] == 'gathered' || _arrKeys[_iTmp] == 'alive_HeroParty' || _arrKeys[_iTmp] == 'reveal_speaker' || _arrKeys[_iTmp] == 'queued' )
			{
				bool _bTmp = false;
				_dictTmp.get( _arrKeys[_iTmp], _bTmp );
				printDialog( "  - '"+_arrKeys[_iTmp]+"'; '"+_bTmp+"'" );
			}
			else 
			{
				string _stgTmp = "";
				_dictTmp.get( _arrKeys[_iTmp], _stgTmp );
				printDialog( "  - '"+_arrKeys[_iTmp]+"'; '"+_stgTmp+"'" );
			}
		}
	}
	void Dialogue_AddToQueue( string _stgQueue, string _stgKey, dictionary _dictInfos )
	{
		// simply print out basic information, about what was added to the queue
		string _stgName;
		string _stgTopic;
		_dictInfos.get('Creature', _stgName);
		_dictInfos.get('Topic', _stgTopic);
		
		if(m_bDia_tickerEnabled)
			printDialogDictionary( _dictInfos );

		// build key
		//string _stgKey = _stgName+";"+_stgTopic;
		dictionary _dictQueue = DialogHelper_GetQueue( _stgQueue ); 
		if ( _stgQueue == 'Bantern' )
			_stgKey = _stgTopic;
		else
			_stgKey =  _dictQueue.getKeys().length()+";"+_stgKey;
		_dictQueue.set( _stgKey, _dictInfos );
		m_dictDialogueQueues.set( _stgQueue, _dictQueue );

		// Handling in which timer-queue everything goes.
		if ( _stgQueue == 'Shoutout' )
			DialogQueue_Shoutout( _stgKey );
		else if ( _stgQueue == 'Shoutout_Special' )
			Dialog_ShoutoutImproved( _stgKey );
		else if ( _stgQueue == 'GenerallyReady' )
			m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogQueue_GenerallyReady), 1, _stgKey );		
		else if ( _stgQueue == 'Timed' ) 
		{
			uint _iTimer = 0;
			_dictInfos.get( 'seconds', _iTimer );
			m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogQueue_Timed), _iTimer, _stgKey );
		}
		else if ( _stgQueue == 'Bantern' )
		{
			uint _iTimer = 0;
			_dictInfos.get( 'seconds', _iTimer );
			m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogBantern_Start), _iTimer, _stgKey );		
		}

		// Dialogs
		if ( _stgQueue == 'Dialog' )
			DialogQueue_Dialog( _stgKey );
		else if ( _stgQueue == 'Dialog_Important' )
			DialogQueue_Important( _stgKey );

		printDialog( "QUEUE-"+_stgQueue+"; Creature '"+_stgName+"', '"+_stgTopic+"' - Key: '"+_stgKey+"'" );
	}

	// ------------------------------------------------------------------------
	// ONLY USED IN THE LevelBase INTERNALLY!!!!!! DONT USE IT ANYWHERE ELSE!!!
	dictionary m_dictTemporarilySaved;
	void InternShoutout( dictionary _dictTmp )
	{
		// don't shoot anything at all, when dialogues are blocked
		if (m_bDialogueBlocked)
			return;

		string 	_stgTMP_CreatureName;
		string 	_stgTMP_ArticyContainerName;
		string 	_stgTMP_ArticyTopicName;
		
		_dictTmp.get( 'Creature', _stgTMP_CreatureName);
		_dictTmp.get( 'Container', _stgTMP_ArticyContainerName);
		_dictTmp.get( 'Topic', _stgTMP_ArticyTopicName);
		
		if ( _stgTMP_CreatureName == '' || _stgTMP_ArticyTopicName == '' )
			return;

		if( _dictTmp.exists('stop_party') ) 
		{
			bool _bTMP_StopHeroParty;
			_dictTmp.get( 'stop_party', _bTMP_StopHeroParty);
			if (_bTMP_StopHeroParty)
				m_Reference.GetHeroParty(m_iPlayerFaction).Stop();
		}
		// reveal, if its configured
		if( _dictTmp.exists('reveal_speaker') ) 
		{
			bool _bTmp = false;
			_dictTmp.get( 'reveal_speaker', _bTmp);
			if (_bTmp)
				CreatureReveal(_stgTMP_CreatureName);
		}

		printDialog( " - Internal Shoutout || Creature Name: '"+_stgTMP_CreatureName+"', Container '"+_stgTMP_ArticyContainerName+"', Topic '"+_stgTMP_ArticyTopicName+"'." );

		if( m_Reference.GetCreatureByName( _stgTMP_CreatureName ).IsInDialogue() )
		{
			m_Reference.GetCreatureByName( _stgTMP_CreatureName ).CancelDialogue();
			m_dictTemporarilySaved = _dictTmp;
			m_Reference.SetTimerMS( TOnTimerEvent(@this.InternShoutout_waitSec), 250 );	
		}
		else 
		{
			m_Reference.GetCreatureByName( _stgTMP_CreatureName ).Shoutout( m_Reference, _stgTMP_ArticyContainerName, _stgTMP_ArticyTopicName, false );
			m_dictCurrentShoutoutsHappening.set( _stgTMP_CreatureName, _stgTMP_ArticyTopicName );
			m_Reference.SetTimer( TOnTimerUserDataEvent(@this.InternShoutout_check), 1, _stgTMP_CreatureName+";"+_stgTMP_ArticyTopicName );
		}
	}
	bool InternShoutout_waitSec()
	{
		string 	_stgTMP_CreatureName;
		string 	_stgTMP_ArticyContainerName;
		string 	_stgTMP_ArticyTopicName;
		
		m_dictTemporarilySaved.get( 'Creature', _stgTMP_CreatureName);
		m_dictTemporarilySaved.get( 'Container', _stgTMP_ArticyContainerName);
		m_dictTemporarilySaved.get( 'Topic', _stgTMP_ArticyTopicName);

		m_Reference.GetCreatureByName( _stgTMP_CreatureName ).Shoutout( m_Reference, _stgTMP_ArticyContainerName, _stgTMP_ArticyTopicName, false );
		m_dictCurrentShoutoutsHappening.set( _stgTMP_CreatureName, _stgTMP_ArticyTopicName );
		m_Reference.SetTimer( TOnTimerUserDataEvent(@this.InternShoutout_check), 1, _stgTMP_CreatureName+";"+_stgTMP_ArticyTopicName );

		return true;
	}

	bool InternShoutout_check( const string& in _stgTmp )
	{
		string _stgName = 	_stgTmp.substr( 0, (_stgTmp.findFirst(";")) );
		string _stgTopic = 	_stgTmp.substr( (_stgTmp.findFirst(";")+1), -1 );
		bool _bIsBantern = false;
		if( _stgTopic.findFirst(';bantern;', 0) != -1 )
			_bIsBantern = true;

		//_stgTopic = _stgTopic.substr(0, _stgTmp.findFirst(";"));

		string _registeredTopic = '';
		m_dictCurrentShoutoutsHappening.get(_stgName, _registeredTopic);

		if( m_Reference.GetCreatureByName(_stgName).IsInDialogue() && _registeredTopic == _stgTopic )
		{
			//printDialog( _stgName+";"+_stgTopic+", still in dialogue." );
		}
		else if ( _registeredTopic != _stgTopic )
		{
			printDialog( _stgName+";"+_stgTopic+", topic was interrupted with another started Dialogue." );
			return true;	
		}
		else
		{
			//if ( m_bDia_tickerEnabled)
				//printDialog( _stgName+";"+_stgTopic+", topic was normally finished. (bantern: "+_bIsBantern+")" );
			m_dictCurrentShoutoutsHappening.delete(_stgName);
			return true;	
		} 
		return false;
	}
	// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
	
	// bool _bCheckDialogues, bool _bCheckCombat, bool _bCheckGathered, bool _bCheckPartyAlive, bool _bStopHeroParty, bool _bRevealSpeaker, bool _bQueued, uint timer
	void DialogCheck_Testing_I()
	{
		DialogShoutout_Special( m_stgAvatar, m_stgAvatar, "M1_SO_Wasteland", true, false, false, true, false, false, false, 1 );
	}
	void DialogCheck_Testing_II()
	{
		DialogShoutout_Special( m_stgAvatar, m_stgAvatar, "M1_SO_Amazing", true, true, false, true, false, false, true, 1 );
	}
	void DialogCheck_Testing_III()
	{
		DialogShoutout_Special( m_stgAvatar, m_stgAvatar, "M1_BN_ExplorationBanter_01", true, false, true, false, false, false, true, 0 );
	}
	void DialogCheck_Testing_IV()
	{
		DialogShoutoutTimed( m_stgHero_Isgrimm, m_stgHero_Isgrimm, "MD1_13_SO_TurretSO", false, 1);
	}
	void DialogCheck_Testing_V()
	{
		DialogShoutout_Important( m_stgAvatar, m_stgAvatar, "M1_BN_ExplorationBanter_01", "Undergast_the_Weaver", array <string> = {} );
	}
	void DialogCheck_Testing_VI()
	{
		DialogTalkTo( m_stgHero_Undergast, m_stgAvatar, m_stgAvatar, "M1_BN_ExplorationBanter_01" );
	}

	void DialogCheck_Bantern()
	{
		DialogBantern( m_stgAvatar, m_stgAvatar, "M1_BN_ExplorationBanter_01", 5 );
	}

	void DialogCheck_PrintQueue( string _stgQueue )
	{
		dictionary _dictQueue = DialogHelper_GetQueue( _stgQueue );

		array <string> _arrQueueOrder = _dictQueue.getKeys();
		_arrQueueOrder.sortAsc();
		if( _arrQueueOrder.length() > 0 )
		{
			printDialog( "QUEUE-"+_stgQueue+": length '"+_arrQueueOrder.length()+"'" );
			// this printout was for testing
			for( uint _iTmp = 0; _iTmp < _arrQueueOrder.length(); _iTmp++ )
				printDialog( " - element '"+_arrQueueOrder[_iTmp]+"'" );
		}
	}
	void DialogCheck_PrintQueues()
	{
		array <string> _arrQueueKeys = m_dictDialogueQueues.getKeys();
		for( uint _iTmp = 0; _iTmp < _arrQueueKeys.length(); _iTmp++ )
		{
			DialogCheck_PrintQueue( _arrQueueKeys[_iTmp] );
		}
	}

	// ----------------------------------------------------------------------------------------------------------- REGISTERING EVENTS
	// normal shoutout, but still checks if at least the main speaker is alive
	void DialogShoutout ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, bool _bStopHeroParty )
	{
		Dialogue_AddToQueue( 'Shoutout', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = {{'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'stop_party', _bStopHeroParty} } 
		);
	}
	
	// same as normal shoutout, but queued!
	void DialogShoutout_Special ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, bool _bCheckDialogues, bool _bCheckCombat, bool _bCheckGathered, bool _bCheckPartyAlive, bool _bRevealSpeaker, bool _bStopHeroParty, bool _bQueued, uint timer )
	{
		Dialogue_AddToQueue( 'Shoutout_Special', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = {{'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, 
			{'not_in_dialogue', _bCheckDialogues}, {'combat', _bCheckCombat}, {'gathered', _bCheckGathered}, {'alive_HeroParty', _bCheckPartyAlive}, {'stop_party', _bStopHeroParty}, {'reveal_speaker', _bRevealSpeaker}, {'queued', _bQueued}, {'seconds', timer} } 
		);
	}

	// checks for: 
	// not in combat, hero party alive, 
	void DialogShoutoutWhenReady ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, bool _bStopHeroParty )
	{
		Dialogue_AddToQueue( 'GenerallyReady', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = {{'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'alive_HeroParty', true}, {'stop_party', _bStopHeroParty} } 
		);
	}

	// starts in the given seconds
	void DialogShoutoutTimed ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, bool _bStopHeroParty, uint _iSeconds )
	{
		Dialogue_AddToQueue( 'Timed', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = { {'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'queued', true}, {'stop_party', _bStopHeroParty}, {'seconds', _iSeconds} } 
		);
	}
	

	// Legacy - simply uses the special function
	void DialogShoutoutOutOfCombat ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, bool _bStopHeroParty )
	{
		DialogShoutout_Special( _stgCreatureName, _stgArticyContainerName, _stgArticyTopicName, false, true, false, false, _bStopHeroParty, false, false, 0 ); 
	}
	void DialogShoutoutReveal ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName )
	{
		DialogShoutout_Special( _stgCreatureName, _stgArticyContainerName, _stgArticyTopicName, false, true, false, false, false, true, false, 0 ); 
	}

	// DialogShoutoutReveal

	// Creature 1 walks to the current position 2
	// If hero party assembled - dialogue starts directly
	// when not, then the NPC stands there, waiting, with Dialog topic enabled
	void DialogTalkTo ( string _stgCreatureName_Initiator, string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName )
	{
		Dialogue_AddToQueue( 'Dialog', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = { {'Creature', _stgCreatureName}, {'Creature_Initiator', _stgCreatureName_Initiator}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName} } 
		);
	}

	// Same as DialogTalkTo - only that the NPC starts an event, once the player enters and they are generally ready
	void DialogTalkToQueued ( string _stgCreatureName_Initiator, string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName )
	{
		Dialogue_AddToQueue( 'Dialog', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = { {'Creature', _stgCreatureName}, {'Creature_Initiator', _stgCreatureName_Initiator}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'queued', true} } 
		);
	}

	// checks, and revives the hero party if needed and right now 
	// The Creature given and the Hero Party are teleported to the position here
	// interrupts everything
	void DialogShoutout_Important ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, string _stgPosition, array <string> _stgCreaturesToGet )
	{
		Dialogue_AddToQueue( 'Dialog_Important', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = { {'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'Additional_Speakers', _stgCreaturesToGet}, {'Position', _stgPosition} } 
		);
	}

	// Same as the DialogTalkTo - only with a dictionary for staging! How fancy. 
	void DialogShoutout_ImportantAndStaged ( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, dictionary _dictStageInformations, array <string> _stgCreaturesToGet )
	{
		Dialogue_AddToQueue( 'Dialog_Important', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = { {'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'Additional_Speakers', _stgCreaturesToGet}, {'Staging', _dictStageInformations} } 
		);
	}


	// --------------------------------------------------------------------- TIMER EVENTS
	dictionary DialogHelper_GetQueue ( string _stgQueue )
	{
		dictionary _dictTmp; 
		m_dictDialogueQueues.get( _stgQueue, _dictTmp);
		return _dictTmp;
	}
	
	dictionary DialogHelper_GetInfo( string _stgQueue, string _stgPosition, bool _bDel )
	{
		//printDialog("- getting '"+_stgQueue+"', position: '"+_stgPosition+"'");
		string _stgKey = "";
		dictionary _dictQueue = DialogHelper_GetQueue( _stgQueue );
		array <string> _arrQueueOrder = _dictQueue.getKeys();
		_arrQueueOrder.sortAsc();

		dictionary _tmp;
		uint _iQueuePos = 0;
		if( _stgPosition == 'Last' )
			_iQueuePos = _arrQueueOrder.length()-1;
		else if( _stgPosition == 'First' )
			_iQueuePos = 0;
		else if( _stgPosition == 'Random' )
			_iQueuePos = m_Reference.GetRandom().GetInteger(0, int(_arrQueueOrder.length()-1));
		
		if( _stgPosition.findFirst('Key;',0) != -1 )
			_stgKey = _stgPosition.substr( _stgPosition.findFirst(';',0)+1, -1 ); 
		else
			_stgKey = _arrQueueOrder[_iQueuePos];	
		
		_dictQueue.get( _stgKey, _tmp ); 
		if(_bDel)
		{
			_dictQueue.delete( _stgKey );
			m_dictDialogueQueues.set( _stgQueue, _dictQueue );
		}

		return _tmp;
	}
	string DialogHelper_GetFrom_Stg( string _stgQueue, string _stgPosition, string _stgToGet )
	{
		string _stgKey = "";
		dictionary _dictQueue = DialogHelper_GetQueue( _stgQueue );
		array <string> _arrQueueOrder = _dictQueue.getKeys();
		_arrQueueOrder.sortAsc();

		if( _arrQueueOrder.length() == 0 )
			return "";

		dictionary _tmp;
		uint _iQueuePos = 0;
		if( _stgPosition == 'Last' )
			_iQueuePos = _arrQueueOrder.length()-1;
		else if( _stgPosition == 'First' )
			_iQueuePos = 0;
		else if( _stgPosition == 'Random' )
			_iQueuePos = m_Reference.GetRandom().GetInteger(0, int(_arrQueueOrder.length()-1));
		
		if( _stgPosition.findFirst('Key;',0) != -1 )
			_stgKey = _stgPosition.substr( _stgPosition.findFirst(';',0)+1, -1 ); 
		else
			_stgKey = _arrQueueOrder[_iQueuePos];	

		_dictQueue.get( _stgKey, _tmp ); 
		string _stgCreatureName = "";
		_tmp.get( _stgToGet, _stgCreatureName );
		return _stgCreatureName;
	}
	/*string DialogHelper_GetFromKey_Stg( string _stgQueue, string _stgKey, string _stgToGet )
	{
		dictionary _dictQueue = DialogHelper_GetQueue( _stgQueue );

	}*/
	uint DialogHelper_GetFrom_Int( dictionary _dictTmp, string _stgGet )
	{
		uint _tmp = 0;
		_dictTmp.get(_stgGet, _tmp);
		return _tmp;
	}
	bool DialogHelper_GetFrom_Bool( dictionary _dictTmp, string _stgGet )
	{
		bool _tmp = false;
		_dictTmp.get(_stgGet, _tmp);
		return _tmp;
	}

	dictionary DialogHelper_Check( dictionary _tmp )
	{
		dictionary _dictFullfilled;
		if( DialogHelper_GetFrom_Bool(_tmp,'not_in_dialogue') )
			_dictFullfilled.set( 'not_in_dialogue', DialogCheck_PartyNotInDialogue() );
		if( DialogHelper_GetFrom_Bool(_tmp,'combat') )
			_dictFullfilled.set( 'combat', DialogCheck_NotInCombat(false) );
		if( DialogHelper_GetFrom_Bool(_tmp,'gathered') )
			_dictFullfilled.set( 'gathered', DialogCheck_IsGathered(false) );
		if( DialogHelper_GetFrom_Bool(_tmp,'alive_HeroParty') )
			_dictFullfilled.set( 'alive_HeroParty', DialogCheck_PartyAlive(false) );
		return _dictFullfilled;
	}
	bool DialogHelper_CheckAllTrue( dictionary _dictTmp )
	{
		array <string> _arrKeys = _dictTmp.getKeys();
		for( uint _iTmp = 0; _iTmp < _arrKeys.length() ; _iTmp++ )
		{
			bool _bTmp = false;
			_dictTmp.get( _arrKeys[_iTmp], _bTmp );
			if( !_bTmp )
				return false;
		}
		return true;
	}
	string DialogHelper_CheckAllTrue_print( dictionary _dictTmp )
	{
		string _stgPrint = "";
		array <string> _arrKeys = _dictTmp.getKeys();
		for( uint _iTmp = 0; _iTmp < _arrKeys.length() ; _iTmp++ )
		{
			bool _bTmp = false;
			_dictTmp.get( _arrKeys[_iTmp], _bTmp );
			_stgPrint += "("+_arrKeys[_iTmp]+";"+_bTmp+")";
		}
		return _stgPrint;
	}

	// obviously check, if the speaker is alive
	void DialogQueue_Shoutout( string _stgKey )
	{
		string _stgSpeaker = DialogHelper_GetFrom_Stg('Shoutout','First','Creature');
		InternShoutout( DialogHelper_GetInfo('Shoutout','Key;'+_stgKey,true) );
		if( m_Reference.GetCreatureByName(_stgSpeaker).Exists() || m_Reference.GetCreatureByName(_stgSpeaker).GetCurrentHP() != 0 )
			printNote( "speaker '"+_stgSpeaker+"' isn't alive or doesn't exist." );
	}
	
	// this is a connection point, where this shoutout is pushed into different queues, depending on which elements where set
	void Dialog_ShoutoutImproved( string _stgKey )
	{
		dictionary _tmp = DialogHelper_GetInfo('Shoutout_Special','Key;'+_stgKey,false);
		
		// timer has highest priority
		if ( DialogHelper_GetFrom_Int( _tmp,'seconds' ) > 0)
		{
			m_Reference.SetTimer( TOnTimerEvent(@this.DialogQueue_Timed_II), DialogHelper_GetFrom_Int(_tmp,'seconds') );
		}
		else 
		{
			// currently fullfilled 
			dictionary _dictFullfilled = DialogHelper_Check( _tmp );
			if (DialogHelper_CheckAllTrue(_dictFullfilled))
				InternShoutout( DialogHelper_GetInfo('Shoutout_Special','First',true) ); 
			else 
				m_Reference.SetTimer( TOnTimerEvent(@this.DialogQueue_ShoutoutImproved), 1 );	
		}
	}
	bool m_bDia_CameDirectly = false;
	bool DialogQueue_Timed_II()
	{
		m_bDia_CameDirectly = true;
		m_Reference.SetTimer( TOnTimerEvent(@this.DialogQueue_ShoutoutImproved), 1 );
		return true;
	}
	bool DialogQueue_ShoutoutImproved()
	{
		dictionary _tmp = DialogHelper_GetInfo('Shoutout_Special','First',false);
		dictionary _dictFullfilled = DialogHelper_Check( _tmp );

		if ( DialogHelper_CheckAllTrue(_dictFullfilled) && m_bDia_CameDirectly == true ) 
		{
			InternShoutout( DialogHelper_GetInfo('Shoutout_Special','First',true) ); 
			return true;
		}
		m_bDia_CameDirectly = false;

		if( DialogHelper_CheckAllTrue(_dictFullfilled) )
		{
			m_iDiaWait_SpecialReady_wait++;
			if (m_bDia_tickerEnabled)
				printDialog( "- special shoutout, TICK '"+m_iDiaWait_SpecialReady_wait+"-"+m_iDiaWait_SpecialReady+"'" );
			if ( m_iDiaWait_SpecialReady_wait == m_iDiaWait_SpecialReady )
			{
				m_iDiaWait_SpecialReady_wait = 0;
				InternShoutout( DialogHelper_GetInfo('Shoutout_Special','First',true) ); 
				return true;
			}
		}
		else if ( !DialogHelper_GetFrom_Bool(_tmp,'queued') )
		{
			printDialog( "Shoutout is blocked and not queued - it's stopped now." );
			DialogHelper_GetInfo('Shoutout_Special','First',true);
			return true;
		}
		else
		{
			m_iDiaWait_SpecialReady_wait = 0;
			if (m_bDia_tickerEnabled)
				printDialog( "Special Shoutout not ready yet - "+DialogHelper_CheckAllTrue_print(_dictFullfilled)+" ." );
		}
		
		return false; 
	}
	
	bool DialogQueue_GenerallyReady( const string& in _stgKey )
	{
		if ( HeroPartyReadyForDialogue() && HeroPartyIsAlive() && DialogCheck_IsGathered( false ) )
		{
			m_iDiaWait_GenerallyReady_wait++;
			if (m_bDia_tickerEnabled)
				printDialog( "- generally ready, TICK '"+m_iDiaWait_GenerallyReady_wait+"-"+m_iDiaWait_GenerallyReady+"'" );

			if ( m_iDiaWait_GenerallyReady_wait == m_iDiaWait_GenerallyReady )
			{
				m_iDiaWait_GenerallyReady_wait = 0;
				InternShoutout( DialogHelper_GetInfo('GenerallyReady','Key;'+_stgKey,true) ); 

				return true;
			}
		}
		else
		{
			m_iDiaWait_GenerallyReady_wait = 0;
			if( m_bDia_tickerEnabled )
				printDialog( "generally waiting for the hero party to be ready." );
		}

		return false;
	}

	bool DialogQueue_Timed ( const string& in _stgKey )
	{
		dictionary _tmp = DialogHelper_GetInfo('Timed','Key;'+_stgKey,false);
		InternShoutout( DialogHelper_GetInfo('Timed','Key;'+_stgKey,true) ); 
		return true;
	}

	// let the person walk to the position, when finished, check if the dialogue is ready
	// if not -> enable the Dialogue Topic, and wait, until the Player is ready again
	bool DialogQueue_Dialog ( string _stgKey )
	{
		dictionary _tmp = DialogHelper_GetInfo('Dialog','Key;'+_stgKey,false);
		bool _bQueued = false;
		if( _tmp.exists('queued') )
			_tmp.get('queued', _bQueued);
		
		// dictionary = { {'Creature', _stgCreatureName}, {'Creature_Initiator', _stgCreatureName_Initiator}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'queued', true} } 
		
		Creature _crtInitiator = m_Reference.GetCreatureByName( DialogHelper_GetFrom_Stg('Dialog','First','Creature_Initiator') );
		Creature _crtTalkedTo = m_Reference.GetCreatureByName( DialogHelper_GetFrom_Stg('Dialog','First','Creature') );

		_crtInitiator.Talk( m_Reference, _crtTalkedTo, DialogHelper_GetFrom_Stg('Dialog','First','Container'), DialogHelper_GetFrom_Stg('Dialog','First','Topic'), _bQueued, m_iPlayerFaction, 0 );
		DialogHelper_GetInfo('Dialog','First',true);

		return true;
	}

	bool DialogQueue_Important (  string _stgKey )
	{
		PlayerHeroControlDisable();
		m_bDialogueBlocked = true;
		
		// stopping all dialogues from everyone
		array <string> _arrDialogues = m_dictCurrentShoutoutsHappening.getKeys();
		for( uint _itmp = 0; _itmp < _arrDialogues.length() ; _itmp++ )
		{
			m_Reference.GetCreatureByName( _arrDialogues[_itmp] ).CancelDialogue();
			m_dictCurrentShoutoutsHappening.delete( _arrDialogues[_itmp] );
		}

		// stopping hero party
		m_Reference.GetHeroParty(m_iPlayerFaction).Stop();

		m_Reference.FadeToBlack( m_iPlayerFaction, uint8(-1), 1000);
		m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogQueue_Important_I), 1, _stgKey );

		return false;		
	}
	bool DialogQueue_Important_I( const string& in _stgKey )
	{
		// getting the position and exact staging
		dictionary _tmp = DialogHelper_GetInfo('Dialog_Important','Key;'+_stgKey,false);
		string _stgPosition = DialogHelper_GetFrom_Stg('Dialog_Important','First','Position');
		Entity _entTmp;
		if( m_Reference.GetCreatureByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetCreatureByName(_stgPosition).GetId() );
		else if( m_Reference.GetLogicObjectByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetLogicObjectByName(_stgPosition).GetId() );
		else 
		{
			printDialog( "Dialog Important: couldn't find the psoition '"+_stgPosition+"', not as character, nor as LogicObject" );
			_entTmp = m_Reference.GetEntityById( m_Reference.GetCreatureByName(m_stgAvatar).GetId() );
		}

		// Managing hero party and camera
		m_Reference.GetHeroParty( m_iPlayerFaction ).Gather(_entTmp);
		m_Reference.FocusCamera( m_iPlayerFaction, _entTmp );

		// teleport additional NPCs that should also be present
		array <string> _arrTmp;
		_tmp.get('Additional_Speakers', _arrTmp);
		for( uint _iTmp = 0; _iTmp < _arrTmp.length() ; _iTmp++ )
		{
			printDialog( "- Additional speaker: '"+_arrTmp[_iTmp]+"'" );
			m_Reference.GetCreatureByName( _arrTmp[_iTmp] ).ReviveInstant( m_Reference );
			m_Reference.GetCreatureByName( _arrTmp[_iTmp] ).Teleport(m_Reference, _entTmp);
		}
		
		
		m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogQueue_Important_II), 1, _stgPosition );

		return true;
	}
	bool DialogQueue_Important_II( const string& in _stgPosition )
	{
		Entity _entTmp;
		if( m_Reference.GetCreatureByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetCreatureByName(_stgPosition).GetId() );
		else if( m_Reference.GetLogicObjectByName(_stgPosition).Exists() )
			_entTmp = m_Reference.GetEntityById( m_Reference.GetLogicObjectByName(_stgPosition).GetId() );

		// stage the hero's a little
		array <Creature>@ _crtHeroes = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers ();
		for (uint _iTmp = 0; _iTmp < _crtHeroes.length(); _iTmp++)
		{
			if( _crtHeroes[_iTmp].GetDescriptionName() == m_stgAvatar)
				_crtHeroes[_iTmp].GoTo( m_Reference, _entTmp, m_iDiaDis_TalkDistance_Avatar, m_iDiaDis_TalkDistance_Avatar, true );
			else	
				_crtHeroes[_iTmp].GoTo( m_Reference, _entTmp, m_iDiaDis_TalkDistance, m_iDiaDis_TalkDistance, true );
		}

		m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogQueue_Important_III), 1, _stgPosition );
		return true;
	}
	bool DialogQueue_Important_III( const string& in _stgPosition )
	{
		// look at position
		HeroPartyLookAt( _stgPosition );

		dictionary _tmp = DialogHelper_GetInfo('Dialog_Important','First',false);
		array <string> _arrTmp;
		_tmp.get('Additional_Speakers', _arrTmp);
		for( uint _iTmp = 0; _iTmp < _arrTmp.length() ; _iTmp++ )
			CreatureLookAt( _arrTmp[_iTmp], _stgPosition );

		// fade to normal
		m_Reference.FadeFromBlack( m_iPlayerFaction, uint8(-1), 1000);
		m_Reference.SetTimer( TOnTimerEvent(@this.DialogQueue_Important_IV), 1 );
		return true;
	}
	bool DialogQueue_Important_IV()
	{
		m_bDialogueBlocked = false;
		PlayerHeroControlEnable();
		InternShoutout( DialogHelper_GetInfo('Dialog_Important','First',true) ); 
		return true;
	}

	// checks if anyone, anywhere is currenlty in a dialogue or so
	bool DialogCheck_AnyoneInDialogue()
	{
		array <string> _crtCreaturesInDialogue = m_dictCurrentShoutoutsHappening.getKeys();
		if( _crtCreaturesInDialogue.length() > 0 )
			return false;
		return true;
	}
	string DialogCheck_GetDialogueCreature()
	{
		array <string> _crtCreaturesInDialogue = m_dictCurrentShoutoutsHappening.getKeys();
		if( _crtCreaturesInDialogue.length() > 0 )
			return _crtCreaturesInDialogue[0];

		return '';
	}
	
	// checks if still in Combat
	bool DialogCheck_NotInCombat( bool _bShowNotification )
	{
		// ok, now, this is getting complex. Bantern should be able to be stopped
		// so, we check fist: if in dialogue
		if ( m_Reference.IsCampaignFactionInCombat() == false )// && m_Reference.GetCreatureByName(m_stgAvatar).IsBusy() == false )
			return true;

		if(_bShowNotification)
			m_Reference.ShowNotification( m_iPlayerFaction, "HeroPartyEndCombat", m_Reference.GetCreatureByName(m_stgAvatar) );
			
		return false;
	}

	// simple check if alive
	bool DialogCheck_PartyAlive( bool _bShowNotification )
	{
		if( HeroPartyIsAlive() )
			return true;
		else 
		{
			if (_bShowNotification)
				m_Reference.ShowNotification( m_iPlayerFaction, "HeroPartyGather", m_Reference.GetCreatureByName(m_stgAvatar) );
			return false;
		}
	}

	// checks if alive, and gathered
	bool DialogCheck_IsGathered( bool _bShowNotification )
	{
		if( HeroPartyIsAlive() && m_Reference.GetHeroParty( m_iPlayerFaction ).IsGathered( _bShowNotification ))
			return true;
		return false;
	}


	// checks, that no one in the party is currently in a dialogue
	bool DialogCheck_PartyNotInDialogue()
	{
		// checking first, if any hero party member is in a dialogue
		bool _bNotInDialogue = true;
		array <Creature> _arrParty = m_Reference.GetHeroParty( m_iPlayerFaction ).GetMembers();
		for ( uint _iTmp = 0; _iTmp < _arrParty.length() ; _iTmp++ )
			if ( _arrParty[_iTmp].IsInDialogue() )
				_bNotInDialogue = false;
		
		// if yes - next going to check, in which dialogue they are
		// if it's a bantern, we are going to interrupt it
		if( !_bNotInDialogue )
		{
			dictionary _dictBanterns = DialogHelper_GetQueue( 'Bantern' );
			// now we need to check if the current dialogue is a bantern - if yes, stopt it and return true
			array <string> _arrDialogues = m_dictCurrentShoutoutsHappening.getKeys();
			for( uint _itmp = 0; _itmp < _arrDialogues.length() ; _itmp++ )
			{
				string _stgTopic = "";
				m_dictCurrentShoutoutsHappening.get( _arrDialogues[_itmp], _stgTopic );
				//printNote( " - checking if the current Dialog  '"+_arrDialogues[_itmp]+";"+_stgTopic+"' is a bantern" );
				if( _dictBanterns.exists( _stgTopic ) )
					_bNotInDialogue = true;
			}
		}
		return _bNotInDialogue;
	}

	
	// Generic Dialogue
	bool OnDialogShoutout_Generic_WrongWay( Creature& in _Creature )
	{
		DialogShoutout( m_stgAvatar, m_stgAvatar, "Generic_WrongWay", true );
		return true;
	}
	// Generic Dialogue
	void DialogShoutout_Generic_ValuableLoot()
	{
		DialogShoutout(m_stgAvatar, m_stgAvatar, "Generic_ValuableLoot_" + m_Reference.GetRandom().GetInteger(1, 3), true );
	}
	


	// --- HERO BANTERN --------------------------------------------------------------------------------------------------
	// -------------------------------------------------------------------------------------------------------------------
	// Shoutout Bantern stuff

	//array <string> m_arrCurrentBanternQueue; // display's the current order and queue, in which the topics where registered. Once a Bantern is finished, it's deleted from here
	//uint m_iCurrentBanternPosition = 	0;
	
	bool m_bAllowBantern = 				true;
	bool m_bInBantern = 				false;
	bool m_bInBantern_Finished = 		true;

	uint m_bTriedABantern = 			0;
	uint m_bTriedABantern_Max = 		3;

	void DialogBantern_Enable( bool _bEnable )
	{
		m_bAllowBantern = _bEnable;
	}
	void DialogBantern( string _stgCreatureName, string _stgArticyContainerName, string _stgArticyTopicName, uint _iSeconds )
	{
		printDialog( "Dialog Banter - Registering a new topic, Informations: Creature: '"+_stgCreatureName+"', ContainerName '"+_stgArticyContainerName+"', Topic '"+_stgArticyTopicName+"', plays in '"+_iSeconds+"' seconds." );
		Dialogue_AddToQueue( 'Bantern', (_stgCreatureName+";"+_stgArticyTopicName),
			dictionary = {{'Creature', _stgCreatureName}, {'Container', _stgArticyContainerName}, {'Topic', _stgArticyTopicName}, {'stop_party', false}, {'stop_party', false}, {'seconds', _iSeconds} } 
		);

	}
	bool DialogBantern_Start( const string& in _stgKey )
	{
		// Check, if the bantern is the next in line. If not: check later here again. 
		// If yes, then start the DialogBantern_Timer.
		if (m_bDia_tickerEnabled)
			printDialog( "BANTERN: '"+_stgKey+"' is about to start - getting to the check stage. (allow banterns: "+m_bAllowBantern+")" );

		m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogBantern_Timer), 1, _stgKey );
		return true;
	}
	bool DialogBantern_Timer( const string& in _stgKey )
	{
		if( !m_bAllowBantern )
			return false;

		// check if the situation is ready for the dialogue
		// if not, return this method directly, and start another timed event with the check time
		if ( DialogCheck_NotInCombat(false) && DialogCheck_PartyAlive(false) && DialogCheck_IsGathered(false) && DialogCheck_AnyoneInDialogue() )
		{
			m_iDiaWait_BanternReady_wait++; 
			if (m_bDia_tickerEnabled)
				printDialog( "BANTERN: TICK'ing '"+m_iDiaWait_BanternReady_wait+"-"+m_iDiaWait_BanternReady+"'" );
			
			if( m_iDiaWait_BanternReady_wait == m_iDiaWait_BanternReady )
			{
				m_iDiaWait_BanternReady_wait = 0;

				dictionary _dictInformations;
				dictionary _dictQueue = DialogHelper_GetQueue( 'Bantern' );
				_dictQueue.get( _stgKey, _dictInformations );

				if( m_bTriedABantern == m_bTriedABantern_Max ) 
				{
					printDialog( "BANTERN: tried it '"+m_bTriedABantern+"' times to play '"+_stgKey+"' - stopping now." );
					ArticyBanternFinished(_stgKey);
					m_bTriedABantern = 0;
					return true;
				}
				// get the current data's
				InternShoutout( _dictInformations ); 
				m_bTriedABantern++;
				m_bInBantern = true;
				m_bInBantern_Finished = false;
				
				// register all the events, to handle the interruption of the banterns
				m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogBantern_Timer_checking), 1, _stgKey );
				return true;
			}
		}
		else 
		{
			m_iDiaWait_BanternReady_wait = 0;
			if( m_bDia_tickerEnabled )
				printDialog( "BANTERN: still waiting - not in combat: "+DialogCheck_NotInCombat(false)+", alive: "+DialogCheck_PartyAlive(false)+", gathered: "+DialogCheck_IsGathered(false)+", no one else in dialogue: "+DialogCheck_AnyoneInDialogue()+"" );
		}

		return false;
	}
	bool DialogBantern_Timer_checking( const string& in _stgKey )
	{
		dictionary _dictQueue = DialogHelper_GetQueue( 'Bantern' );
		if( m_bInBantern_Finished || !_dictQueue.exists(_stgKey) )
			return true;
		
		if( !DialogCheck_NotInCombat(false) || !DialogCheck_PartyAlive(false) )
		{
			printDialog( "BANTERN: interrupted, Combat "+DialogCheck_NotInCombat(false)+", party alive '"+DialogCheck_PartyAlive(false)+"'" );
			HeroPartyStopDialogues();
			return true;
		}
		return false;
	}
	
	void ArticyBanternFinished ( string _stgTopic )
	{
		printDialog( "BANTERN: Bantern Topic "+_stgTopic+" was finished" );
		dictionary _dictQueue = DialogHelper_GetQueue( 'Bantern' );
		if( _dictQueue.exists( _stgTopic ) )
		{
			m_bInBantern = false;
			m_bInBantern_Finished = true;
			_dictQueue.delete( _stgTopic );	
			m_dictDialogueQueues.set( 'Bantern', _dictQueue );
		}
	}
	void ArticyBanternInterrupt ( string _stgTopic )
	{
		printDialog( "BANTERN: Bantern Topic '"+_stgTopic+"' was interrupted - waiting for the next chance" );
		m_bInBantern = false;
		m_Reference.SetTimer( TOnTimerUserDataEvent(@this.DialogBantern_Timer), 1, _stgTopic );
	}

}
