BUBBLE_PROX_N = 100.0 ;

-- RandomEncounter muskcard
function run_muskcard( encounterLevel, encounterPosX, encounterPosY )
	local name = "muskcard" ;
	
	muskcardvars = {} ;
	muskcardvars.musketeers = {} ;
	muskcardvars.cardinalsguards = {} ;
	
	local maxMusketeers = 3 ;
	local numMusketeers = randomInt( 2, maxMusketeers + 1 ) ;
	
	local maxCardinalsGuards = 3 ;
	local numCardinalsGuards = randomInt( 2, maxCardinalsGuards + 1 ) ;
	
	local index = 1 ;
	while ( index <= numMusketeers ) do
		local xPos = encounterPosX ;
		local yPos = encounterPosY ;
		if ( index == 1 ) then
			xPos = encounterPosX - randomInt( 25, 30 ) ;
			yPos = encounterPosY ;
		elseif ( index == 2 ) then
			xPos = encounterPosX - randomInt( 25, 30 ) ;
			yPos = encounterPosY - randomInt( 40, 50 ) ;
		elseif ( index == 3 ) then
			xPos = encounterPosX - randomInt( 25, 30 ) ;
			yPos = encounterPosY + randomInt( 40, 50 ) ;
		end

		muskcardvars.musketeers[ index ] = 
			createTempCharacter( getString( "musketeer" ), encounterLevel, xPos, yPos ) ;
		
		local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;

		setStatsCalculatorStatic( muskcardvars.musketeers[ index ], attack, defence, attack, attack ) ;
		setMeleeWeapon( muskcardvars.musketeers[ index ], "sword_1" ) ;
		setBaseFaceDirection( muskcardvars.musketeers[ index ], 1, 0 ) ;
		
		randomDressMusketeer( muskcardvars.musketeers[ index ], 0.0, randomInt( 0, 99999 ) ) ;
		setCharacterSlowDamage( muskcardvars.musketeers[ index ], true ) ;
						
		index = index + 1 ;
	end
	
	local index = 1 ;
	while ( index <= numCardinalsGuards ) do
		local xPos = encounterPosX ;
		local yPos = encounterPosY ;
		if ( index == 1 ) then
			xPos = encounterPosX + randomInt( 25, 30 ) ;
			yPos = encounterPosY ;
		elseif ( index == 2 ) then
			xPos = encounterPosX + randomInt( 25, 30 ) ;
			yPos = encounterPosY - randomInt( 40, 50 ) ;
		elseif ( index == 3 ) then
			xPos = encounterPosX + randomInt( 25, 30 ) ;
			yPos = encounterPosY + randomInt( 40, 50 ) ;
		end

		muskcardvars.cardinalsguards[ index ] = 
			createTempCharacter( getString( "cardinalsguard" ), encounterLevel, xPos, yPos ) ;
		
		local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;

		setStatsCalculatorStatic( muskcardvars.cardinalsguards[ index ], attack, defence, attack, attack ) ;
		setMeleeWeapon( muskcardvars.cardinalsguards[ index ], "sword_1" ) ;
		setBaseFaceDirection( muskcardvars.cardinalsguards[ index ], 1, 0 ) ;
		
		randomDressCardinalsGuard( muskcardvars.cardinalsguards[ index ], 0.0, randomInt( 0, 99999 ) ) ;
		setCharacterSlowDamage( muskcardvars.cardinalsguards[ index ], true ) ;
				
		index = index + 1 ;
	end
	
	for muskKey, muskValue in pairs( muskcardvars.musketeers ) do 
		for cardKey, cardValue in pairs( muskcardvars.cardinalsguards ) do 
			makeEnemies( muskValue, cardValue ) ;
		end	
	end
				
	local alreadyShowedMessageSinceClose = false ;	
	local acceptedEncounter = false ;
	
	local dartagnanHelps = musksKnowDartagnan( ) ; --getCharacterHonour( "dartagnan" ) > 15 ;
	
	while ( not acceptedEncounter ) do
		
		muskcardvars.waitingTalk = {} ;
		
		for key, value in pairs( muskcardvars.musketeers ) do 
			table.insert( muskcardvars.waitingTalk,
				 setWaitingForTalk( "dartagnan", value, false ) ) ;
		end
		
		for key, value in pairs( muskcardvars.cardinalsguards ) do 
			table.insert( muskcardvars.waitingTalk,
				 setWaitingForTalk( "dartagnan", value, false ) ) ;
		end
		
		while ( not ( hasAnyWaitingTalkOccured( muskcardvars.waitingTalk ) ) ) do
			if ( dartagnanHelps ) then
				local messageDist = 200.0 ;
				local bubbleCloseProx = 250.0 ;
				if ( distanceBetweenCharacters( "dartagnan", muskcardvars.musketeers[ 1 ] ) < messageDist ) then
					if ( not alreadyShowedMessageSinceClose ) then
						if ( not characterHasOpenBubble( muskcardvars.musketeers[ 1 ] ) ) then
							--local bubInd = characterSay( muskcardvars.musketeers[ 1 ], true, -1, bubbleCloseProx, true, getString( "muskcard_1" ) ) ;
							--autoDeleteBubble( bubInd ) ;
							
							local bubInd = characterSay( muskcardvars.musketeers[ 1 ], false, 6.0, bubbleCloseProx, true, getString( "muskcard_1" ) ) ;
							autoDeleteBubble( bubInd ) ;
							
							alreadyShowedMessageSinceClose = true ;
						end
					end
				end
				
				if ( distanceBetweenCharacters( "dartagnan", muskcardvars.musketeers[ 1 ] ) > bubbleCloseProx ) then
					alreadyShowedMessageSinceClose = false ;
				end
			end
			
			coroutine.yield( ) ;
		end
		
		setDoneWaitingTalkAll( muskcardvars.waitingTalk ) ;
		muskcardvars.waitingTalk = {} ;

		setEncounterFreezeGame( name, true ) ;
		--setNonChatTalkFreeze( true ) ;
		closeCharacterBubble( muskcardvars.musketeers[ 1 ] ) ; -- in case he still has his bubble open

		if ( dartagnanHelps ) then
			sayAndWait( muskcardvars.musketeers[ 1 ], getString( "muskcard_3" ) ) ;
	
			local bubInd = characterSay( "dartagnan", false, -1, -1, true, "", getString( "muskcard_4" ), getString( "muskcard_5" ) ) ;
			local option = waitForBubbleOption( bubInd ) ;
			if ( option == 0 ) then
				acceptedEncounter = true ;
			elseif ( option == 1 ) then
				acceptedEncounter = false ;
			end
		else
			sayAndWait( muskcardvars.musketeers[ 1 ], getString( "muskcard_2" ) ) ;
		end
		
		setEncounterFreezeGame( name, false ) ;
		--setNonChatTalkFreeze( false ) ;
	end
	
	for key, value in pairs( muskcardvars.musketeers ) do
		setRatioHealth( value, 1.0 ) ;
		setCharacterSlowDamage( value, false ) ;
	end

	for key, value in pairs( muskcardvars.cardinalsguards ) do
		setRatioHealth( value, 1.0 ) ;
		setCharacterSlowDamage( value, false ) ;
	end	
	
	for key, value in pairs( muskcardvars.cardinalsguards ) do
		makeEnemies( "dartagnan", value ) ;
	end
	
	while ( isAnyCharacterInTableAlive( muskcardvars.cardinalsguards ) ) do
		coroutine.yield( ) ;
	end

	-- after all are dead
	
	for key, value in pairs( muskcardvars.musketeers ) do
		if ( characterExists( value ) and isCharacterAlive( value ) ) then
			setBaseChatString( value, getString( "muskcard_6" ) ) ;
		end
	end
end

function isdone_muskcard( )
	if ( not ( muskcardvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( muskcardvars.musketeers ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		for key, value in pairs( muskcardvars.cardinalsguards ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_muskcard( )
	if ( not ( muskcardvars == nil ) ) then
		for key, value in pairs( muskcardvars.musketeers ) do 
			deleteTempCharacter( value ) ;
		end
		
		for key, value in pairs( muskcardvars.cardinalsguards ) do 
			deleteTempCharacter( value ) ;
		end
		
		for key, value in pairs( muskcardvars.waitingTalk ) do 
			setDoneWaitingTalk( value ) ;
		end

		muskcardvars = nil ;
	end
end

-- RandomEncounter ladyinsult
function setLadyInsultEnemy( enemy )
	local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;

	setStatsCalculatorStatic( enemy, attack, defence, attack, attack ) ;
	randomDressEnemy( enemy, dressLevel, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( enemy, "sword_1" ) ;
	setBaseFaceCharacter( enemy, ladyinsultvars.victim ) ;
end

function run_ladyinsult( encounterLevel, encounterPosX, encounterPosY )
	local name = "ladyinsult" ;
	
	ladyinsultvars = {} ;
	ladyinsultvars.characters = {} ;
	ladyinsultvars.victim = nil ;
	
	local type = "distressedwoman" ;
	
	local victim = createTempCharacter( getString( type ), encounterLevel, encounterPosX - 20, encounterPosY + 15 ) ;	
	
	setWoman( victim, true ) ;
	dress_randladyinsultlady( victim ) ;
	
	ladyinsultvars.victim = victim ;
	
	local maxEnemies = 2 ;
	local numEnemies = 	randomInt( 1, maxEnemies + 1 ) ;
	
	local index = 1 ;
	while ( index <= numEnemies ) do
		local xPos = encounterPosX ;
		local yPos = encounterPosY ;
		if ( index == 1 ) then
			xPos = encounterPosX + randomInt( 15, 25 ) ;
			yPos = encounterPosY - randomInt( 15, 25 ) ;
		elseif ( index == 2 ) then
			xPos = encounterPosX + randomInt( 30, 40 ) ;
			yPos = encounterPosY + randomInt( 25, 35 ) ;
		end

		ladyinsultvars.characters[ index ] = 
			createTempCharacter( getString( "ruffian" ), encounterLevel, xPos, yPos ) ;
		setLadyInsultEnemy( ladyinsultvars.characters[ index ] ) ;
		
		setBaseFaceCharacter( ladyinsultvars.characters[ index ], ladyinsultvars.victim ) ;
				
		index = index + 1 ;
	end
	
	setBaseFaceCharacter( ladyinsultvars.victim, ladyinsultvars.characters[ 1 ] ) ;
			
	local alreadyShowedMessageSinceClose = false ;	
	local acceptedEncounter = false ;
	
	while ( not acceptedEncounter ) do
		
		ladyinsultvars.waitingTalk = {} ;
		ladyinsultvars.victimWait = nil ;
		
		for key, value in pairs( ladyinsultvars.characters ) do 
			ladyinsultvars.waitingTalk[ key ] = setWaitingForTalk( 
				"dartagnan", value, false ) ;
		end
		
		ladyinsultvars.victimWait = setWaitingForTalk( "dartagnan", ladyinsultvars.victim, false ) ;
		
		while ( not ( hasAnyWaitingTalkOccured( ladyinsultvars.waitingTalk ) or 
			hasWaitingTalkOccured( ladyinsultvars.victimWait ) ) ) do
			
			local messageDist = 200.0 ;
			local bubbleCloseProx = 250.0 ;
			if ( distanceBetweenCharacters( "dartagnan", ladyinsultvars.victim ) < messageDist ) then
				if ( not alreadyShowedMessageSinceClose ) then
					if ( not characterHasOpenBubble( ladyinsultvars.victim ) ) then
						--local bubInd = characterSay( ladyinsultvars.victim, true, -1, bubbleCloseProx, true, getString( "ladyinsult_1" ) ) ;
						--autoDeleteBubble( bubInd ) ;
						
						local bubInd = characterSay( ladyinsultvars.victim, false, 6.0, bubbleCloseProx, true, getString( "ladyinsult_1" ) ) ;
						autoDeleteBubble( bubInd ) ;
						
						alreadyShowedMessageSinceClose = true ;
					end
				end
			end
			
			if ( distanceBetweenCharacters( "dartagnan", ladyinsultvars.victim ) > bubbleCloseProx ) then
				alreadyShowedMessageSinceClose = false ;
			end
			
			coroutine.yield( ) ;
		end
		
		setDoneWaitingTalkAll( ladyinsultvars.waitingTalk ) ;
		setDoneWaitingTalk( ladyinsultvars.victimWait ) ;
		ladyinsultvars.waitingTalk = {} ;
		ladyinsultvars.victimWait = nil ;

		setEncounterFreezeGame( name, true ) ;
		--setNonChatTalkFreeze( true ) ;

		setIgnoreFreeze( ladyinsultvars.victim, true ) ;
		setIgnoreFreeze( ladyinsultvars.characters[ 1 ], true ) ;
		setBaseFaceCharacter( ladyinsultvars.characters[ 1 ], "dartagnan" ) ;
		setBaseFaceCharacter( ladyinsultvars.victim, "dartagnan" ) ;
		faceCharacter( "dartagnan", ladyinsultvars.victim ) ;

		closeCharacterBubble( ladyinsultvars.victim ) ; -- in case he still has his bubble open

		sayAndWait( "dartagnan", getString( "ladyinsult_2" ) ) ;
		sayAndWait( ladyinsultvars.victim, getString( "ladyinsult_3" ) ) ;
		sayAndWait( ladyinsultvars.characters[ 1 ], getString( "ladyinsult_4" ) ) ;

		local bubInd = characterSay( "dartagnan", false, -1, -1, true, "", getString( "ladyinsult_5" ), getString( "ladyinsult_6" ) ) ;
		local option = waitForBubbleOption( bubInd ) ;
		if ( option == 0 ) then
			acceptedEncounter = true ;
		elseif ( option == 1 ) then
			acceptedEncounter = false ;
		end
		setBaseFaceCharacter( ladyinsultvars.victim, ladyinsultvars.characters[ 1 ] ) ;
		setBaseFaceCharacter( ladyinsultvars.characters[ 1 ], ladyinsultvars.victim ) ;
		setIgnoreFreeze( ladyinsultvars.victim, false ) ;
		setIgnoreFreeze( ladyinsultvars.characters[ 1 ], false ) ;
		setEncounterFreezeGame( name, false ) ;
		--setNonChatTalkFreeze( false ) ;
	end
	
	for key, value in pairs( ladyinsultvars.characters ) do
		makeEnemies( "dartagnan", value ) ;
	end
	
	setBaseFaceCharacter( ladyinsultvars.victim, "dartagnan" ) ;
	
	setAvoidFight( ladyinsultvars.victim, true ) ;
	--addGoalGetToPoint( ladyinsultvars.victim, encounterPosX - 70, encounterPosY + 70, encounterLevel, false ) ;

	while ( isAnyCharacterInTableAlive( ladyinsultvars.characters ) ) do
		coroutine.yield( ) ;
	end

	-- after all are dead
	
	ladyinsultvars.victimWait = setWaitingForTalk( 
		"dartagnan", ladyinsultvars.victim, false ) ;
	while ( not hasWaitingTalkOccured( ladyinsultvars.victimWait ) ) do
		coroutine.yield( ) ;
	end
	setDoneWaitingTalk( ladyinsultvars.victimWait ) ;
	ladyinsultvars.victimWait = nil ;

	setEncounterFreezeGame( name, true ) ;
	--setNonChatTalkFreeze( true ) ;
	local bubInd = characterSay( ladyinsultvars.victim, true, -1, -1, true, getString( "thankyoureward" ) ) ;
	waitForBubbleClosed( bubInd ) ;
	local victimPosX, victimPosY = getCharacterPos( ladyinsultvars.victim ) ;
	setEncounterFreezeGame( name, false ) ;
	--setNonChatTalkFreeze( false ) ;

	local enemyLootValue = getRewardLootValue( numEnemies ) ;
	local lootPosX = victimPosX + 30 ;
	local lootPosY = victimPosY ;

	-- just give money
	createMoney( "", enemyLootValue, encounterLevel, lootPosX, lootPosY, true ) ;
	
	setBaseChatString( ladyinsultvars.victim, getString( "thankyoumonsieur" ) ) ;
end

function isdone_ladyinsult( )
	if ( not ( ladyinsultvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( ladyinsultvars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		-- check distance from victim
		local dist = distanceBetweenCharacters( "dartagnan", ladyinsultvars.victim ) ;
		local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
		local otherLevel = getCharacterFunctionalLevel( ladyinsultvars.victim ) ;
		local sameLevel = playerLevel == otherLevel ;
		local closeEnough = dist < distFromAllCharsToFinish ;
		if ( sameLevel and closeEnough ) then
			finished = false ;
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_ladyinsult( )
	if ( not ( ladyinsultvars == nil ) ) then
		for key, value in pairs( ladyinsultvars.characters ) do 
			deleteTempCharacter( value ) ;
		end
		
		deleteTempCharacter( ladyinsultvars.victim ) ;
		
		for key, value in pairs( ladyinsultvars.waitingTalk ) do 
			setDoneWaitingTalk( value ) ;
		end
		
		if ( ladyinsultvars.victimWait ~= nil ) then
			setDoneWaitingTalk( ladyinsultvars.victimWait ) ;
		end
		
		ladyinsultvars = nil ;
	end
end

-- RandomEncounter highwayrobbery
function setHighwayRobberyEnemy( enemy )
	local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;

	setStatsCalculatorStatic( enemy, attack, defence, attack, attack ) ;
	randomDressEnemy( enemy, dressLevel, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( enemy, "sword_1" ) ;
	setBaseFaceCharacter( enemy, highwayrobberyvars.victim ) ;
end

function run_highwayrobbery( encounterLevel, encounterPosX, encounterPosY )
	local name = "highwayrobbery" ;
	
	highwayrobberyvars = {} ;
	highwayrobberyvars.characters = {} ;
	highwayrobberyvars.victim = nil ;
	
	local type = "none" ;
	local randomType = randomInt( 1, 7 ) ;
	if ( randomType == 1 ) then
		type = "baker_m" ;
	elseif ( randomType == 2 ) then
		type = "tailor_m" ;
	elseif ( randomType == 3 ) then
		type = "armorer_m" ;
	elseif ( randomType == 4 ) then
		type = "jeweller_m" ;
	elseif ( randomType == 5 ) then
		type = "seamstress" ;
	elseif ( randomType == 6 ) then
		type = "distressedwoman" ;
	end
	
	local victim = createTempCharacter( getString( type ), encounterLevel, encounterPosX, encounterPosY ) ;	
	
	if ( type == "baker_m" ) then
		dress_randbaker( victim ) ;
	elseif ( type == "tailor_m" ) then
		dress_randtailor( victim ) ;
	elseif ( type == "armorer_m" ) then
		dress_randarmorer( victim ) ;
	elseif ( type == "jeweller_m" ) then
		dress_randjeweller( victim ) ;
	elseif ( type == "seamstress" ) then
		setWoman( victim, true ) ;
		dress_randseamstress( victim ) ;
	elseif ( type == "distressedwoman" ) then
		setWoman( victim, true ) ;
		dress_randdistressedwoman( victim ) ;
	end
	
	highwayrobberyvars.victim = victim ;
	
	local maxEnemies = 6 ;
	local numEnemies = 	randomInt( 2, maxEnemies + 1 ) ;
	
	local bottomEnemyPosY = encounterPosY + 45.0 ;
	local topEnemyPosY = encounterPosY - 45.0 ;
	
	local index = 1 ;
	while ( index <= numEnemies ) do
		local xPos = encounterPosX ;
		local yPos = encounterPosY ;
		if ( index == 1 ) then
			xPos = encounterPosX ;
			yPos = bottomEnemyPosY ;
		elseif ( index == 2 ) then
			xPos = encounterPosX ;
			yPos = topEnemyPosY ;
		elseif ( index == 3 ) then
			xPos = encounterPosX - randomInt( 50, 60 ) ;
			yPos = encounterPosY - randomInt( 20, 30 ) ;
		elseif ( index == 4 ) then
			xPos = encounterPosX + randomInt( 50, 60 ) ;
			yPos = encounterPosY + randomInt( 20, 30 ) ;
		elseif ( index == 5 ) then
			xPos = encounterPosX - randomInt( 50, 60 ) ;
			yPos = encounterPosY + randomInt( 20, 30 ) ;
		elseif ( index == 6 ) then
			xPos = encounterPosX + randomInt( 50, 60 ) ;
			yPos = encounterPosY - randomInt( 20, 30 ) ;
		end

		highwayrobberyvars.characters[ index ] = 
			createTempCharacter( getString( "thief" ), encounterLevel, xPos, yPos ) ;
		setHighwayRobberyEnemy( highwayrobberyvars.characters[ index ] ) ;
		
		index = index + 1 ;
	end
	
		
	local goingToPoint = -1 ;
			
	local alreadyShowedMessageSinceClose = false ;	
	local acceptedEncounter = false ;
	
	while ( not acceptedEncounter ) do
		
		highwayrobberyvars.waitingTalk = {} ;
		highwayrobberyvars.victimWait = nil ;
		
		for key, value in pairs( highwayrobberyvars.characters ) do 
			highwayrobberyvars.waitingTalk[ key ] = setWaitingForTalk( 
				"dartagnan", value, false ) ;
		end
		
		highwayrobberyvars.victimWait = setWaitingForTalk( "dartagnan", highwayrobberyvars.victim, false ) ;
		
		while ( not ( hasAnyWaitingTalkOccured( highwayrobberyvars.waitingTalk ) or 
			hasWaitingTalkOccured( highwayrobberyvars.victimWait ) ) ) do
			local destLeft = encounterPosX - 20 ;
			local destRight = encounterPosX + 20 ;
			local destBottom = bottomEnemyPosY - 20 ;
			local destTop = topEnemyPosY + 20 ;
			if ( not characterHasGoal( highwayrobberyvars.victim ) ) then
				if ( goingToPoint == -1 ) then
					goingToPoint = 0 ;
					addGoalGetToPoint( highwayrobberyvars.victim, destLeft, destBottom, encounterLevel, false ) ;
					clearGoals( highwayrobberyvars.characters[ 1 ] ) ;
					addGoalGetToPoint( highwayrobberyvars.characters[ 1 ], destLeft, bottomEnemyPosY, encounterLevel, false ) ;
				elseif ( goingToPoint == 0 ) then
					goingToPoint = 1 ;
					addGoalGetToPoint( highwayrobberyvars.victim, destRight, destTop, encounterLevel, false ) ;
					clearGoals( highwayrobberyvars.characters[ 2 ] ) ;
					addGoalGetToPoint( highwayrobberyvars.characters[ 2 ], destRight, topEnemyPosY, encounterLevel, false ) ;
				elseif ( goingToPoint == 1 ) then
					goingToPoint = 2 ;
					addGoalGetToPoint( highwayrobberyvars.victim, destRight, destBottom, encounterLevel, false ) ;
					clearGoals( highwayrobberyvars.characters[ 1 ] ) ;
					addGoalGetToPoint( highwayrobberyvars.characters[ 1 ], destRight, bottomEnemyPosY, encounterLevel, false ) ;
				elseif ( goingToPoint == 2 ) then
					goingToPoint = -1 ;
					addGoalGetToPoint( highwayrobberyvars.victim, destLeft, destTop, encounterLevel, false ) ;
					clearGoals( highwayrobberyvars.characters[ 2 ] ) ;
					addGoalGetToPoint( highwayrobberyvars.characters[ 2 ], destLeft, topEnemyPosY, encounterLevel, false ) ;
				end
			end
			
			local messageDist = 200.0 ;
			local bubbleCloseProx = 250.0 ;
			if ( distanceBetweenCharacters( "dartagnan", highwayrobberyvars.victim ) < messageDist ) then
				if ( not alreadyShowedMessageSinceClose ) then
					if ( not characterHasOpenBubble( highwayrobberyvars.victim ) ) then
						--local bubInd = characterSay( highwayrobberyvars.victim, true, -1, bubbleCloseProx, true, getString( "highwayrobbery_1" ) ) ;
						--autoDeleteBubble( bubInd ) ;
						
						local bubInd = characterSay( highwayrobberyvars.victim, false, 6.0, bubbleCloseProx, true, getString( "highwayrobbery_1" ) ) ;
						autoDeleteBubble( bubInd ) ;
						
						alreadyShowedMessageSinceClose = true ;
					end
				end
			end
			
			if ( distanceBetweenCharacters( "dartagnan", highwayrobberyvars.victim ) > bubbleCloseProx ) then
				alreadyShowedMessageSinceClose = false ;
			end
			
			coroutine.yield( ) ;
		end
		
		setDoneWaitingTalkAll( highwayrobberyvars.waitingTalk ) ;
		setDoneWaitingTalk( highwayrobberyvars.victimWait ) ;
		highwayrobberyvars.waitingTalk = {} ;
		highwayrobberyvars.victimWait = nil ;

		setEncounterFreezeGame( name, true ) ;
		--setNonChatTalkFreeze( true ) ;

		setIgnoreFreeze( highwayrobberyvars.victim, true ) ;
		clearGoals( highwayrobberyvars.victim ) ;
		setStateMessageIdle( highwayrobberyvars.victim ) ;
		faceCharacter( highwayrobberyvars.victim, "dartagnan" ) ;
		faceCharacter( "dartagnan", highwayrobberyvars.victim ) ;

		local bubInd = characterSay( highwayrobberyvars.victim, true, -1, -1, true, getString( "highwayrobbery_2" ) ) ;
		waitForBubbleClosed( bubInd ) ;
		bubInd = characterSay( "dartagnan", false, -1, -1, true, "", getString( "highwayrobbery_3" ), getString( "highwayrobbery_4" ) ) ;
		local option = waitForBubbleOption( bubInd ) ;
		if ( option == 0 ) then
			acceptedEncounter = true ;
		elseif ( option == 1 ) then
			acceptedEncounter = false ;
		end
		setIgnoreFreeze( highwayrobberyvars.victim, false ) ;
		setEncounterFreezeGame( name, false ) ;
		--setNonChatTalkFreeze( false ) ;
	end
	
	clearGoals( highwayrobberyvars.characters[1] ) ;
	clearGoals( highwayrobberyvars.characters[2] ) ;
	clearGoals( highwayrobberyvars.victim ) ;
		
	for key, value in pairs( highwayrobberyvars.characters ) do
		makeEnemies( "dartagnan", value ) ;
	end
	
	setBaseFaceCharacter( highwayrobberyvars.victim, "dartagnan" ) ;
	
	setAvoidFight( highwayrobberyvars.victim, true ) ;
	--addGoalGetToPoint( highwayrobberyvars.victim, encounterPosX - 70, encounterPosY + 70, encounterLevel, false ) ;

	while ( isAnyCharacterInTableAlive( highwayrobberyvars.characters ) ) do
		coroutine.yield( ) ;
	end

	-- after all are dead
	
	highwayrobberyvars.victimWait = setWaitingForTalk( 
		"dartagnan", highwayrobberyvars.victim, false ) ;
	while ( not hasWaitingTalkOccured( highwayrobberyvars.victimWait ) ) do
		coroutine.yield( ) ;
	end
	setDoneWaitingTalk( highwayrobberyvars.victimWait ) ;
	highwayrobberyvars.victimWait = nil ;

	setEncounterFreezeGame( name, true ) ;
	--setNonChatTalkFreeze( true ) ;
	local bubInd = characterSay( highwayrobberyvars.victim, true, -1, -1, true, getString( "thankyoureward" ) ) ;
	waitForBubbleClosed( bubInd ) ;
	local victimPosX, victimPosY = getCharacterPos( highwayrobberyvars.victim ) ;
	setEncounterFreezeGame( name, false ) ;
	--setNonChatTalkFreeze( false ) ;

	local enemyLootValue = getRewardLootValue( numEnemies ) ;
	local lootPosX = victimPosX + 30 ;
	local lootPosY = victimPosY ;

	if ( type == "tailor" or type == "seamstress" ) then
		-- clothing
		local item = getItemTypeWorthAround( enemyLootValue, true, true, true, true, true, false, true, true, true, true, false, false ) ;
		createItem( "", item, encounterLevel, lootPosX, lootPosY, true ) ;
	elseif ( type == "armorer" ) then
		-- sword/gun
		local item = getItemTypeWorthAround( enemyLootValue, false, false, false, false, false, false, false, false, false, false, true, true ) ;
		createItem( "", item, encounterLevel, lootPosX, lootPosY, true ) ;
	elseif ( type == "jeweller" ) then
		-- jewels
		local item = getItemTypeWorthAround( enemyLootValue, false, false, false, false, false, true, false, false, false, false, false, false ) ;
		createItem( "", item, encounterLevel, lootPosX, lootPosY, true ) ;
	else
		-- just give money
		createMoney( "", enemyLootValue, encounterLevel, lootPosX, lootPosY, true ) ;
	end
	
	setBaseChatString( highwayrobberyvars.victim, getString( "thankyoumonsieur" ) ) ;
end

function isdone_highwayrobbery( )
	if ( not ( highwayrobberyvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( highwayrobberyvars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		-- check distance from victim
		local dist = distanceBetweenCharacters( "dartagnan", highwayrobberyvars.victim ) ;
		local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
		local otherLevel = getCharacterFunctionalLevel( highwayrobberyvars.victim ) ;
		local sameLevel = playerLevel == otherLevel ;
		local closeEnough = dist < distFromAllCharsToFinish ;
		if ( sameLevel and closeEnough ) then
			finished = false ;
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_highwayrobbery( )
	if ( not ( highwayrobberyvars == nil ) ) then
		for key, value in pairs( highwayrobberyvars.characters ) do 
			deleteTempCharacter( value ) ;
		end
		
		deleteTempCharacter( highwayrobberyvars.victim ) ;
		
		for key, value in pairs( highwayrobberyvars.waitingTalk ) do 
			setDoneWaitingTalk( value ) ;
		end
		
		if ( highwayrobberyvars.victimWait ~= nil ) then
			setDoneWaitingTalk( highwayrobberyvars.victimWait ) ;
		end
		
		highwayrobberyvars = nil ;
	end
end

function getRandomEncStats( minDifficulty, maxDifficulty )
	local playerCombatLevel = getHighestPlayerCombatLevel( ) ;
	return getRandomEncStatsForCombatLevel( minDifficulty, maxDifficulty, playerCombatLevel ) ;
end

function getRandomEncStatsForCombatLevel( minDifficulty, maxDifficulty, playerCombatLevel )
	local enemyCombatLevel = randomInt( playerCombatLevel + minDifficulty, playerCombatLevel + maxDifficulty + 1 ) ;
	local minCombatLevel = 2 ;
	local maxCombatLevel = 120 ; -- 30 * 4
	if ( enemyCombatLevel < minCombatLevel ) then
		enemyCombatLevel = minCombatLevel ;
	end
	if ( enemyCombatLevel > maxCombatLevel ) then
		enemyCombatLevel = maxCombatLevel ;
	end
	
	local attack = enemyCombatLevel / 2 ;
	local defence = enemyCombatLevel - attack ;
	
	--DEBUG_OUTPUT( "attack " .. attack ) ;
	--DEBUG_OUTPUT( "defence " .. defence ) ;
	
	local dressLevel = 0.0 ;
	if ( enemyCombatLevel < 30.0 ) then
		dressLevel = 0.0 ;
	elseif ( enemyCombatLevel < 60.0 ) then
		dressLevel = 0.5 ;
	else
		dressLevel = 1.0 ;
	end
	
	return attack, defence, dressLevel ;
end

-- RandomEncounter HighwayAmbush
function setHighwayAmbushEnemy( enemy )
	local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;
	
	setStatsCalculatorStatic( enemy, attack, defence, attack, attack ) ;
	randomDressEnemy( enemy, dressLevel, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( enemy, "sword_1" ) ;
	setRangedWeapon( enemy, "musket_matchlock_1" ) ;
	setRangedLoadedRatio( enemy, 1.0 ) ;
	setBaseFaceCharacter( enemy, "dartagnan" ) ;
end

function run_highwayambush( encounterLevel, encounterPosX, encounterPosY )
	local name = "highwayambush" ;
	
	highwayambushvars = {} ;
	highwayambushvars.characters = {} ;

	local maxEnemies = 3 ;
	local numEnemies = 	randomInt( 1, maxEnemies + 1 ) ;
	
	local index = 1 ;
	while ( index <= numEnemies ) do
		local xPos = encounterPosX + randomInt( -70, 70 ) ;
		local yPos = encounterPosY + randomInt( -70, 70 ) ;
		
		highwayambushvars.characters[ index ] = 
			createTempCharacter( getString( "highwayman" ), encounterLevel, xPos, yPos ) ;
		setHighwayAmbushEnemy( highwayambushvars.characters[ index ] ) ;
		makeEnemies( "dartagnan", highwayambushvars.characters[ index ] ) ;
		
		index = index + 1 ;
	end
	
	while ( isAnyCharacterInTableAlive( highwayambushvars.characters ) ) do
		coroutine.yield( ) ;
	end
end

function isdone_highwayambush( )
	if ( not ( highwayambushvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( highwayambushvars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_highwayambush( )
	if ( not ( highwayambushvars == nil ) ) then
		for key, value in pairs( highwayambushvars.characters ) do 
			deleteTempCharacter( value ) ;
		end	
		
		highwayambushvars = nil ;
	end
end

-- RandomEncounter RochellePatrol
function setRochellePatrolEnemy( enemy )
	local attack, defence, dressLevel = getRandomEncStats( -15, -3 ) ;
	local maxStat = 40 ;
	if ( attack > maxStat ) then
		attack = maxStat ;
	end
	
	if ( defence > maxStat ) then
		defence = maxStat ; 
	end
	
	setStatsCalculatorStatic( enemy, attack, defence, attack, attack ) ;
	randomDressRochellais( enemy, 0.5, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( enemy, "sword_1" ) ;
	setRangedWeapon( enemy, "musket_matchlock_1" ) ;
	setRangedLoadedRatio( enemy, 1.0 ) ;
	setBaseFaceCharacter( enemy, "dartagnan" ) ;
end

function run_rochellepatrol( encounterLevel, encounterPosX, encounterPosY )
	local name = "rochellepatrol" ;
	
	rochellepatrolvars = {} ;
	rochellepatrolvars.characters = {} ;

	local maxEnemies = 6 ;
	local numEnemies = 	randomInt( 2, maxEnemies + 1 ) ;
	
	local index = 1 ;
	while ( index <= numEnemies ) do
		local xPos = encounterPosX + randomInt( -70, 70 ) ;
		local yPos = encounterPosY + randomInt( -70, 70 ) ;
		
		rochellepatrolvars.characters[ index ] = 
			createTempCharacter( getString( "rochellais" ), encounterLevel, xPos, yPos ) ;
		setRochellePatrolEnemy( rochellepatrolvars.characters[ index ] ) ;
		makeEnemies( "dartagnan", rochellepatrolvars.characters[ index ] ) ;
		
		index = index + 1 ;
	end
	
	while ( isAnyCharacterInTableAlive( rochellepatrolvars.characters ) ) do
		coroutine.yield( ) ;
	end
end

function isdone_rochellepatrol( )
	if ( not ( rochellepatrolvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( rochellepatrolvars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_rochellepatrol( )
	if ( not ( rochellepatrolvars == nil ) ) then
		for key, value in pairs( rochellepatrolvars.characters ) do 
			deleteTempCharacter( value ) ;
		end	
		
		rochellepatrolvars = nil ;
	end
end

-- RandomEncounter EnglishInsult
function setEnglishInsultEnemy( enemy )
	local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;

	setStatsCalculatorStatic( enemy, attack, defence, attack, attack ) ;
	randomDressEnemy( enemy, dressLevel, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( enemy, "sword_1" ) ;
	setBaseFaceCharacter( enemy, "dartagnan" ) ;
end

function run_englishinsult( encounterLevel, encounterPosX, encounterPosY )
	local name = "englishinsult" ;
	
	englishinsultvars = {} ;
	englishinsultvars.characters = {} ;

	local maxEnemies = 4 ;
	local numEnemies = 	randomInt( 1, maxEnemies + 1 ) ;
	
	local index = 1 ;
	while ( index <= numEnemies ) do
		local xPos = encounterPosX ;
		local yPos = encounterPosY ;
		if ( index == 1 ) then
			xPos = encounterPosX - randomInt( 20, 30 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		elseif ( index == 2 ) then
			xPos = encounterPosX + randomInt( 20, 30 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		elseif ( index == 3 ) then
			xPos = encounterPosX + randomInt( -10, 10 ) ;
			yPos = encounterPosY - randomInt( 20, 30 ) ;
		elseif ( index == 4 ) then
			xPos = encounterPosX + randomInt( -10, 10 ) ;
			yPos = encounterPosY + randomInt( 20, 30 ) ;
		elseif ( index == 5 ) then
			xPos = encounterPosX - randomInt( 40, 50 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		end

		englishinsultvars.characters[ index ] = 
			createTempCharacter( getString( "englishman" ), encounterLevel, xPos, yPos ) ;
		setEnglishInsultEnemy( englishinsultvars.characters[ index ] ) ;
		
		index = index + 1 ;
	end
	
	local alreadyShowedMessageSinceClose = false ;	
	local acceptedEncounter = false ;
	
	while ( not acceptedEncounter ) do
			
		englishinsultvars.waitingTalk = {} ;
		
		for key, value in pairs( englishinsultvars.characters ) do 
			englishinsultvars.waitingTalk[ key ] = setWaitingForTalk( 
				"dartagnan", value, false ) ;
		end
		
		while ( not hasAnyWaitingTalkOccured( englishinsultvars.waitingTalk ) ) do
			local messageDist = 200.0 ;
			local bubbleCloseProx = 250.0 ;
			if ( distanceBetweenCharacters( "dartagnan", englishinsultvars.characters[1] ) < messageDist ) then
				if ( not alreadyShowedMessageSinceClose ) then
					if ( not characterHasOpenBubble( englishinsultvars.characters[1] ) ) then
						local insultText = getString( "englishinsult_1" ) ;
						
						--local bubInd = characterSay( englishinsultvars.characters[1], true, -1, bubbleCloseProx, true, insultText ) ;
						--autoDeleteBubble( bubInd ) ;

						local bubInd = characterSay( englishinsultvars.characters[1], false, 6.0, bubbleCloseProx, true, insultText ) ;
						autoDeleteBubble( bubInd ) ;
						
						alreadyShowedMessageSinceClose = true ;
					end
				end
			end
			
			if ( distanceBetweenCharacters( "dartagnan", englishinsultvars.characters[1] ) > bubbleCloseProx ) then
				alreadyShowedMessageSinceClose = false ;
			end
			
			coroutine.yield( ) ;
		end
		
		setDoneWaitingTalkAll( englishinsultvars.waitingTalk ) ;
		englishinsultvars.waitingTalk = {} ;
		
		setEncounterFreezeGame( name, true ) ;
		--setNonChatTalkFreeze( true ) ;
		faceCharacter( "dartagnan", englishinsultvars.characters[1] ) ;
		closeCharacterBubble( englishinsultvars.characters[1] ) ; -- in case he still has his bubble open

		sayAndWait( "dartagnan", getString( "englishinsult_2" ) ) ;
		sayAndWait( englishinsultvars.characters[1], getString( "englishinsult_3" ) ) ;
		local bubInd = characterSay( "dartagnan", false, -1, -1, true, "", getString( "englishinsult_4" ), getString( "englishinsult_5" ) ) ;
		local option = waitForBubbleOption( bubInd ) ;
		if ( option == 0 ) then
			acceptedEncounter = true ;
		elseif ( option == 1 ) then
			acceptedEncounter = false ;
		end
		setEncounterFreezeGame( name, false ) ;
		--setNonChatTalkFreeze( false ) ;
	end
	
	for key, value in pairs( englishinsultvars.characters ) do
		makeEnemies( "dartagnan", value ) ;
	end
	
	while ( isAnyCharacterInTableAlive( englishinsultvars.characters ) ) do
		coroutine.yield( ) ;
	end
end

function isdone_englishinsult( )
	if ( not ( englishinsultvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( englishinsultvars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_englishinsult( )
	if ( not ( englishinsultvars == nil ) ) then
		for key, value in pairs( englishinsultvars.characters ) do 
			deleteTempCharacter( value ) ;
		end	
		
		for key, value in pairs( englishinsultvars.waitingTalk ) do 
			setDoneWaitingTalk( value ) ;
		end

		englishinsultvars = nil ;
	end
end

-- RandomEncounter CardInsult
function setCardInsultEnemy( enemy )
	local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;

	setStatsCalculatorStatic( enemy, attack, defence, attack, attack ) ;
	randomDressCardinalsGuard( enemy, 0.0, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( enemy, "sword_1" ) ;
	setBaseFaceCharacter( enemy, "dartagnan" ) ;
end

function cardInsultGenerateInsult( )
	local insult = "" ;
	if ( isMissionComplete( "missionrochelle10" ) ) then
		-- musketeer
		insult = getString( "cardinsult_insult3" ) ;
	elseif ( isMissionComplete( "missionparis9" ) ) then
		-- after tennis match
		insult = getString( "cardinsult_insult2" ) ;
	else
		-- nothing
		insult = getString( "cardinsult_insult1" ) ;
	end
	
	return insult ;
end

function run_cardinsult( encounterLevel, encounterPosX, encounterPosY )
	local name = "cardinsult" ;
	
	cardinsultvars = {} ;
	cardinsultvars.characters = {} ;

	local maxEnemies = 5 ;
	local numEnemies = 	randomInt( 2, maxEnemies + 1 ) ;
	
	local index = 1 ;
	while ( index <= numEnemies ) do
		local xPos = encounterPosX ;
		local yPos = encounterPosY ;
		if ( index == 1 ) then
			xPos = encounterPosX - randomInt( 20, 30 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		elseif ( index == 2 ) then
			xPos = encounterPosX + randomInt( 20, 30 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		elseif ( index == 3 ) then
			xPos = encounterPosX + randomInt( -10, 10 ) ;
			yPos = encounterPosY - randomInt( 20, 30 ) ;
		elseif ( index == 4 ) then
			xPos = encounterPosX + randomInt( -10, 10 ) ;
			yPos = encounterPosY + randomInt( 20, 30 ) ;
		elseif ( index == 5 ) then
			xPos = encounterPosX - randomInt( 40, 50 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		end

		cardinsultvars.characters[ index ] = 
			createTempCharacter( getString( "cardinalsguard" ), encounterLevel, xPos, yPos ) ;
		setCardInsultEnemy( cardinsultvars.characters[ index ] ) ;
		
		index = index + 1 ;
	end
	
	local alreadyShowedMessageSinceClose = false ;	
	local acceptedEncounter = false ;
	
	while ( not acceptedEncounter ) do
			
		cardinsultvars.waitingTalk = {} ;
		
		for key, value in pairs( cardinsultvars.characters ) do 
			cardinsultvars.waitingTalk[ key ] = setWaitingForTalk( 
				"dartagnan", value, false ) ;
		end
		
		local insultText = cardInsultGenerateInsult( ) ;
		
		while ( not hasAnyWaitingTalkOccured( cardinsultvars.waitingTalk ) ) do
			local messageDist = 200.0 ;
			local bubbleCloseProx = 250.0 ;
			if ( distanceBetweenCharacters( "dartagnan", cardinsultvars.characters[1] ) < messageDist ) then
				if ( not alreadyShowedMessageSinceClose ) then
					if ( not characterHasOpenBubble( cardinsultvars.characters[1] ) ) then
						insultText = cardInsultGenerateInsult( ) ;
						
						--local bubInd = characterSay( cardinsultvars.characters[1], true, -1, bubbleCloseProx, true, insultText ) ;
						--autoDeleteBubble( bubInd ) ;
						
						local bubInd = characterSay( cardinsultvars.characters[1], false, 6.0, bubbleCloseProx, true, insultText ) ;
						autoDeleteBubble( bubInd ) ;
						
						alreadyShowedMessageSinceClose = true ;
					end
				end
			end
			
			if ( distanceBetweenCharacters( "dartagnan", cardinsultvars.characters[1] ) > bubbleCloseProx ) then
				alreadyShowedMessageSinceClose = false ;
			end
			
			coroutine.yield( ) ;
		end
		
		setDoneWaitingTalkAll( cardinsultvars.waitingTalk ) ;
		cardinsultvars.waitingTalk = {} ;
		
		setEncounterFreezeGame( name, true ) ;
		--setNonChatTalkFreeze( true ) ;
		faceCharacter( "dartagnan", cardinsultvars.characters[1] ) ;
		closeCharacterBubble( cardinsultvars.characters[1] ) ; -- in case he still has his bubble open
		
		local bubInd = characterSay( "dartagnan", false, -1, -1, true, "", getString( "cardinsult_reply1" ), getString( "cardinsult_reply2" ) ) ;
		local option = waitForBubbleOption( bubInd ) ;
		if ( option == 0 ) then
			acceptedEncounter = true ;
		elseif ( option == 1 ) then
			acceptedEncounter = false ;
		end
		setEncounterFreezeGame( name, false ) ;
		--setNonChatTalkFreeze( false ) ;
	end
	
	for key, value in pairs( cardinsultvars.characters ) do
		makeEnemies( "dartagnan", value ) ;
	end
	
	while ( isAnyCharacterInTableAlive( cardinsultvars.characters ) ) do
		coroutine.yield( ) ;
	end
end

function isdone_cardinsult( )
	if ( not ( cardinsultvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( cardinsultvars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_cardinsult( )
	if ( not ( cardinsultvars == nil ) ) then
		for key, value in pairs( cardinsultvars.characters ) do 
			deleteTempCharacter( value ) ;
		end	
		
		for key, value in pairs( cardinsultvars.waitingTalk ) do 
			setDoneWaitingTalk( value ) ;
		end

		cardinsultvars = nil ;
	end
end

-- RandomEncounter IndividualInsult
function setIndividualInsultEnemy( enemy )
	local attack, defence, dressLevel = getRandomEncStats( -15, 3 ) ;

	setStatsCalculatorStatic( enemy, attack, defence, attack, attack ) ;
	randomDressEnemy( enemy, dressLevel, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( enemy, "sword_1" ) ;
	setBaseFaceCharacter( enemy, "dartagnan" ) ;
end

function hasAnyWaitingTalkOccured( waitingVars )
	for key, value in pairs( waitingVars ) do 
		if ( hasWaitingTalkOccured( value ) ) then
			return true ;
		end
	end
	
	return false ;
end

function setDoneWaitingTalkAll( waitingVars )
	for key, value in pairs( waitingVars ) do 
		setDoneWaitingTalk( value ) ;
	end
end

function individualInsultGenerateInsult( )
	local sandy = false ;
	local horseBad = false ;
	local horseGood = false ;
	local clothingBad = false ;
	local clothingGood = false ;
	local royal = true ;
	local general = true ;
	
	local playersHorseName = getCharacterOwnedHorseName( "dartagnan" ) ;
	local playerIsDriving = characterIsDriving( "dartagnan" ) ;
	local playerHorseQuality = "none" ;
	if ( hasOwnedHorse( "dartagnan" ) ) then
		playerHorseQuality = getHorseQuality( playersHorseName ) ;
	end

	if ( playerIsDriving ) then
		if ( playersHorseName == "horse1" ) then
			sandy = true ;
		end
		
		if ( playerHorseQuality == "terrible" or playerHorseQuality == "poor" ) then
			horseBad = true ;
		end
		
		if ( playerHorseQuality == "good" or playerHorseQuality == "excellent" ) then
			horseGood = true ;
		end
	end

	local totalClothingHonour = getPlayerClothingHonour( ) ;
	if ( totalClothingHonour <= 8 ) then
		clothingBad = true ;
	end
	
	if ( totalClothingHonour >= 15 ) then
		clothingGood = true ;
	end


	
	-- format: name, number of insults, honour insult
	
	local insultTypes = {} ;
	if ( sandy ) then
		table.insert( insultTypes, { "sandy", 2, true } ) ;
	end
	
	if ( horseBad ) then
		table.insert( insultTypes, { "horsebad", 4, true } ) ;
	end
	
	if ( horseGood ) then
		table.insert( insultTypes, { "horsegood", 3, true } ) ;
	end
	
	if ( clothingBad ) then
		table.insert( insultTypes, { "clothingbad", 4, true } ) ;
	end
	
	if ( clothingGood ) then
		table.insert( insultTypes, { "clothinggood", 3, true } ) ;
	end
	
	if ( royal ) then
		table.insert( insultTypes, { "royal", 5, false } ) ;
	end
	
	if ( general ) then
		table.insert( insultTypes, { "general", 3, true } ) ;
	end
	
	local tableNum = randomInt( 1, table.getn( insultTypes ) + 1 ) ;
	local insultType = insultTypes[ tableNum ] ;
	local insultName = insultType[ 1 ] ;
	local numInsults = insultType[ 2 ] ;
	local honourInsult = insultType[ 3 ] ;
	local insultNum = randomInt( 1, numInsults + 1 ) ;
	
	local insult = getString( "indinsult_insult" .. insultName .. insultNum ) ;
	
	return insult, honourInsult ;
end

function run_individualinsult( encounterLevel, encounterPosX, encounterPosY )
	local name = "individualinsult" ;
	
	individualinsultvars = {} ;
	individualinsultvars.characters = {} ;

	local maxEnemies = 4 ;
	local numEnemies = 	randomInt( 1, maxEnemies + 1 ) ;
	
	local index = 1 ;
	while ( index <= numEnemies ) do
		local xPos = encounterPosX ;
		local yPos = encounterPosY ;
		if ( index == 1 ) then
			xPos = encounterPosX - randomInt( 20, 30 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		elseif ( index == 2 ) then
			xPos = encounterPosX + randomInt( 20, 30 ) ;
			yPos = encounterPosY + randomInt( -10, 10 ) ;
		elseif ( index == 3 ) then
			xPos = encounterPosX + randomInt( -10, 10 ) ;
			yPos = encounterPosY - randomInt( 20, 30 ) ;
		elseif ( index == 4 ) then
			xPos = encounterPosX + randomInt( -10, 10 ) ;
			yPos = encounterPosY + randomInt( 20, 30 ) ;
		end

		individualinsultvars.characters[ index ] = 
			createTempCharacter( getString( "ruffian" ), encounterLevel, xPos, yPos ) ;
		setIndividualInsultEnemy( individualinsultvars.characters[ index ] ) ;
		
		index = index + 1 ;
	end
	
	local alreadyShowedMessageSinceClose = false ;	
	local acceptedEncounter = false ;
	
	while ( not acceptedEncounter ) do
			
		individualinsultvars.waitingTalk = {} ;
		
		for key, value in pairs( individualinsultvars.characters ) do 
			individualinsultvars.waitingTalk[ key ] = setWaitingForTalk( 
				"dartagnan", value, false ) ;
		end
		
		local insultText, insultHonour = individualInsultGenerateInsult( ) ;
		
		while ( not hasAnyWaitingTalkOccured( individualinsultvars.waitingTalk ) ) do
			local messageDist = 200.0 ;
			local bubbleCloseProx = 250.0 ;
			if ( distanceBetweenCharacters( "dartagnan", individualinsultvars.characters[1] ) < messageDist ) then
				if ( not alreadyShowedMessageSinceClose ) then
					if ( not characterHasOpenBubble( individualinsultvars.characters[1] ) ) then
						insultText, insultHonour = individualInsultGenerateInsult( ) ;
						
						--local bubInd = characterSay( individualinsultvars.characters[1], true, -1, bubbleCloseProx, true, insultText ) ;
						--autoDeleteBubble( bubInd ) ;
						
						local bubInd = characterSay( individualinsultvars.characters[1], false, 6.0, bubbleCloseProx, true, insultText ) ;
						autoDeleteBubble( bubInd ) ;
						
						alreadyShowedMessageSinceClose = true ;
					end
				end
			end
			
			if ( distanceBetweenCharacters( "dartagnan", individualinsultvars.characters[1] ) > bubbleCloseProx ) then
				alreadyShowedMessageSinceClose = false ;
			end
			
			coroutine.yield( ) ;
		end
		
		setDoneWaitingTalkAll( individualinsultvars.waitingTalk ) ;
		individualinsultvars.waitingTalk = {} ;
		
		setEncounterFreezeGame( name, true ) ;
		--setNonChatTalkFreeze( true ) ;
		faceCharacter( "dartagnan", individualinsultvars.characters[1] ) ;
		closeCharacterBubble( individualinsultvars.characters[1] ) ; -- in case he still has his bubble open
		local firstReply = getString( "indinsult_reply2" ) ;
		if ( insultHonour ) then
			firstReply = getString( "indinsult_reply1" ) ;
		end
		
		local bubInd = characterSay( "dartagnan", false, -1, -1, true, "", firstReply, getString( "indinsult_reply3" ) ) ;
		local option = waitForBubbleOption( bubInd ) ;
		if ( option == 0 ) then
			acceptedEncounter = true ;
		elseif ( option == 1 ) then
			acceptedEncounter = false ;
		end
		setEncounterFreezeGame( name, false ) ;
		--setNonChatTalkFreeze( false ) ;
	end
	
	for key, value in pairs( individualinsultvars.characters ) do
		makeEnemies( "dartagnan", value ) ;
	end
	
	while ( isAnyCharacterInTableAlive( individualinsultvars.characters ) ) do
		coroutine.yield( ) ;
	end
end

function isdone_individualinsult( )
	if ( not ( individualinsultvars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( individualinsultvars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_individualinsult( )
	if ( not ( individualinsultvars == nil ) ) then
		for key, value in pairs( individualinsultvars.characters ) do 
			deleteTempCharacter( value ) ;
		end	
		
		for key, value in pairs( individualinsultvars.waitingTalk ) do 
			setDoneWaitingTalk( value ) ;
		end

		individualinsultvars = nil ;
	end
end

-- RandomEncounter MusketeerPractice1
function run_musketeerpractice1( encounterLevel, encounterPosX, encounterPosY )
	local name = "musketeerpractice1" ;

	musketeerpracticevars = {} ;
	musketeerpracticevars.characters = {} ;

	musketeerpracticevars.characters[1] = createTempCharacter( getString( "musketeer" ), encounterLevel, encounterPosX - 25, encounterPosY ) ;
	setStatsCalculatorDynamic( musketeerpracticevars.characters[1], -10, -10, 2, 1000, 0.5 ) ;
	setStatsNeverRecalc( musketeerpracticevars.characters[1], true ) ;
	randomDressMusketeer( musketeerpracticevars.characters[1], 0.0, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( musketeerpracticevars.characters[1], "sword_1" ) ;
	setCharacterSlowDamage( musketeerpracticevars.characters[1], true ) ;
	
	musketeerpracticevars.characters[2] = createTempCharacter( getString( "musketeer" ), encounterLevel, encounterPosX + 25, encounterPosY ) ;
	setStatsCalculatorDynamic( musketeerpracticevars.characters[2], -10, -10, 2, 1000, 0.5 ) ;
	setStatsNeverRecalc( musketeerpracticevars.characters[2], true ) ;
	randomDressMusketeer( musketeerpracticevars.characters[2], 0.0, randomInt( 0, 99999 ) ) ;
	setMeleeWeapon( musketeerpracticevars.characters[2], "sword_1" ) ;
	setCharacterSlowDamage( musketeerpracticevars.characters[2], true ) ;

	if ( randomInt( 0, 2 ) == 1 ) then
		musketeerpracticevars.characters[3] = createTempCharacter( getString( "musketeer" ), encounterLevel, encounterPosX, encounterPosY - 50 ) ;
		setStatsCalculatorDynamic( musketeerpracticevars.characters[3], -10, -10, 2, 1000, 0.5 ) ;
		setStatsNeverRecalc( musketeerpracticevars.characters[3], true ) ;
		randomDressMusketeer( musketeerpracticevars.characters[3], 0.0, randomInt( 0, 99999 ) ) ;
		setMeleeWeapon( musketeerpracticevars.characters[3], "sword_1" ) ;
		setCharacterSlowDamage( musketeerpracticevars.characters[3], true ) ;
				
		makeEnemies( musketeerpracticevars.characters[1],
			musketeerpracticevars.characters[2],
			musketeerpracticevars.characters[3] ) ;
	else
		-- only two musketeers
		makeEnemies( musketeerpracticevars.characters[1],
			musketeerpracticevars.characters[2] ) ;
	end
	
	local alreadyShowedMessageSinceClose = false ;	
	
	while ( true ) do
			
		musketeerpracticevars.waitingTalk = {} ;
		
		for i, v in ipairs( musketeerpracticevars.characters ) do
			musketeerpracticevars.waitingTalk[ i ] = setWaitingForTalk(
				"dartagnan", v, false ) ;
		end
		
		local waitingTalkOccured = false ;
		local talkWithCharacter = -1 ;
		while ( not waitingTalkOccured ) do
						
			local messageDist = 200.0 ;
			local bubbleCloseProx = 250.0 ;
			if ( distanceToPoint( "dartagnan", encounterLevel, encounterPosX, encounterPosY ) < messageDist ) then
				if ( not alreadyShowedMessageSinceClose ) then
					local oneHasOpenBubble = false ;
					for i, v in ipairs( musketeerpracticevars.characters ) do
						if ( characterHasOpenBubble( v ) ) then
							oneHasOpenBubble = true ;
						end
					end
					if ( not oneHasOpenBubble ) then
						
						-- randomize comment
						local comment = "" ;
						if ( randomInt( 0, 2 ) == 0 ) then
							comment = getString( "muskpractice_1" ) ;
						else
							comment = getString( "muskpractice_2" ) ;
						end
						
						-- randomize who says it
						local randIndex = randomInt( 1, table.getn( musketeerpracticevars.characters ) + 1 ) ;
						local character = musketeerpracticevars.characters[ randIndex ] ;
						
						--local bubInd = characterSay( character, true, -1, bubbleCloseProx, true, comment ) ;
						--autoDeleteBubble( bubInd ) ;
						
						local bubInd = characterSay( character, false, 6.0, bubbleCloseProx, true, comment ) ;
						autoDeleteBubble( bubInd ) ;
						
						alreadyShowedMessageSinceClose = true ;
					end
				end
			end
			
			if ( distanceToPoint( "dartagnan", encounterLevel, encounterPosX, encounterPosY ) > bubbleCloseProx ) then
				alreadyShowedMessageSinceClose = false ;
			end
			
			coroutine.yield( ) ;
			
			for i, v in ipairs( musketeerpracticevars.waitingTalk ) do
				if ( hasWaitingTalkOccured( v ) ) then
					waitingTalkOccured = true ;
					talkWithCharacter = musketeerpracticevars.characters[ i ] ;
				end
			end
		end
		
		for i, v in ipairs( musketeerpracticevars.waitingTalk ) do
			setDoneWaitingTalk( v ) ;
			musketeerpracticevars.waitingTalk[ i ] = nil ;
		end
		
		setEncounterFreezeGame( name, true ) ;
		
		for i, v in ipairs( musketeerpracticevars.characters ) do
			closeCharacterBubble( v ) ; -- in case he still has his bubble open
		end
		
		local comment = "" ;
		if ( musksKnowDartagnan( ) ) then
			-- they know D'Artagnan
			comment = getString( "muskpractice_4" ) ;
		else
			-- they don't know him
			comment = getString( "muskpractice_3" ) ;
		end
		
		local bubInd = characterSay( talkWithCharacter, true, -1, -1, true, comment ) ;
		waitForBubbleClosed( bubInd ) ;

		setEncounterFreezeGame( name, false ) ;
	end
end

function isdone_musketeerpractice1( )
	if ( not ( musketeerpracticevars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( musketeerpracticevars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_musketeerpractice1( )
	if ( not ( musketeerpracticevars == nil ) ) then
		for key, value in pairs( musketeerpracticevars.characters ) do 
			deleteTempCharacter( value ) ;
		end	
		
		for key, value in pairs( musketeerpracticevars.waitingTalk ) do 
			setDoneWaitingTalk( value ) ;
		end

		musketeerpracticevars = nil ;
	end
end

-- RandomEncounter rochelletowerguard1
-- vertical
function run_rochelletowerguardvert1( encounterLevel, encounterPosX, encounterPosY )
	run_rochelletowerguard1( encounterLevel, encounterPosX, encounterPosY, true ) ;
end

function isdone_rochelletowerguardvert1( )
	return isdone_rochelletowerguard1( ) ;
end	

function finish_rochelletowerguardvert1( )
	finish_rochelletowerguard1( ) ;
end

-- horizontal
function run_rochelletowerguardhor1( encounterLevel, encounterPosX, encounterPosY )
	run_rochelletowerguard1( encounterLevel, encounterPosX, encounterPosY, false ) ;
end

function isdone_rochelletowerguardhor1( )
	return isdone_rochelletowerguard1( ) ;
end	

function finish_rochelletowerguardhor1( )
	finish_rochelletowerguard1( ) ;
end

function setRochelleGuard( guardName )
	local attack, defence, dressLevel = getRandomEncStats( -15, -5 ) ;
	local maxStat = 40 ;
	if ( attack > maxStat ) then
		attack = maxStat ;
	end
	
	if ( defence > maxStat ) then
		defence = maxStat ; 
	end
	
	setStatsCalculatorStatic( guardName, attack, defence, attack, attack ) ;
	setStatsNeverRecalc( guardName, true ) ;
	randomDressRochellais( guardName, 0.5, randomInt( 0, 99999 ) ) ;
	setRangedWeapon( guardName, "musket_matchlock_1" ) ;
	setRangedAttackDist( guardName, 400 ) ; -- shoot from just offscreen
	setRangedLoadedRatio( guardName, 0.9 ) ;
	setBaseFaceCharacter( guardName, "dartagnan" ) ;
	setHasLootDrop( guardName, false ) ;
	setLockRangedStill( guardName, true ) ;
end

function isAnyCharacterInTableAlive( characters )
	for key, value in pairs( characters ) do
		if ( isCharacterAlive( value ) ) then
			return true ;
		end
	end
	
	return false ;
end

function run_rochelletowerguard1( encounterLevel, encounterPosX, encounterPosY, vert )
	local name = "rochelletowerguard1" ;
	
	rochelletowerguard1vars = {} ;
	rochelletowerguard1vars.characters = {} ;

	local maxEnemies = 3 ;
	local numEnemies = 	randomInt( 1, maxEnemies + 1 ) ;
	
	local enemyGap = 80 ;
	local xPos = encounterPosX ;
	local yPos = encounterPosY ;
	
	if ( vert ) then
		yPos = encounterPosY - ( numEnemies / 2 ) * enemyGap ;
	else
		xPos = encounterPosX - ( numEnemies / 2 ) * enemyGap ;
	end
	
	local index = 0 ;
	while ( index < numEnemies ) do
		rochelletowerguard1vars.characters[ index ] = 
			createTempCharacter( getString( "rochellais" ), encounterLevel, xPos, yPos ) ;
		setRochelleGuard( rochelletowerguard1vars.characters[ index ] ) ;
		
		if ( vert ) then
			yPos = yPos + enemyGap ;
		else
			xPos = xPos + enemyGap ;
		end
		
		index = index + 1 ;
	end
	
	for key, value in pairs( rochelletowerguard1vars.characters ) do
		makeEnemies( "dartagnan", value ) ;
	end
	
	while ( isAnyCharacterInTableAlive( rochelletowerguard1vars.characters ) ) do
		coroutine.yield( ) ;
	end	
end

function isdone_rochelletowerguard1( )
	if ( not ( rochelletowerguard1vars == nil ) ) then
		local finished = true ;
		local distFromAllCharsToFinish = 1000.0 ;
		for key, value in pairs( rochelletowerguard1vars.characters ) do 
			local dist = distanceBetweenCharacters( "dartagnan", value ) ;
			local playerLevel = getCharacterFunctionalLevel( "dartagnan" ) ;
			local otherLevel = getCharacterFunctionalLevel( value ) ;
			local sameLevel = playerLevel == otherLevel ;
			local closeEnough = dist < distFromAllCharsToFinish ;
			if ( sameLevel and closeEnough ) then
				finished = false ;
			end
		end
		
		return finished ;
	else
		return true ;
	end
end

function finish_rochelletowerguard1( )
	if ( not ( rochelletowerguard1vars == nil ) ) then
		for key, value in pairs( rochelletowerguard1vars.characters ) do 
			deleteTempCharacter( value ) ;
		end	

		rochelletowerguard1vars = nil ;
	end
end