BUBBLE_PROX_N = 100.0 ;

function wait( seconds )
	local count = 0.0 ;
	while ( count < seconds ) do
		--DEBUG_OUTPUT( "Count: " .. count ) ;
		coroutine.yield( ) ;
		count = count + getDeltaT( ) ;
	end
end

function waitForCameraNotPanning( )
	while ( cameraIsPanning( ) ) do
		coroutine.yield( ) ;
	end
end

function panCameraToWait( x, y, speed, smooth )
	DEBUG_OUTPUT( "Panning camera to : " .. x .. ", " .. y ) ;
	panCameraTo( x, y, speed, smooth ) ;
	waitForCameraNotPanning( ) ;
end

function characterSay( name, says )
	DEBUG_OUTPUT( name .. " says, \"" .. says .. "\"" ) ;
end

function goalWalkToPoint( name, levelName, destX, destY )
	addGoalGetToPointInLevel( name, destX, destY, levelName, false ) ;
	waitForNoGoal( name ) ;
end

function waitForNotPathfinding( name )
	while ( isPathfinding( name ) ) do
		coroutine.yield( ) ;
	end
end

function waitForNoGoal( name )
	while ( characterHasGoal( name ) ) do
		coroutine.yield( ) ;
	end
end

function waitForCharacterOffScreen( name )
	while ( isCharacterOnScreen( name ) ) do
		coroutine.yield( ) ;
	end
end

function waitForBubbleClosed( bubbleIndex )
	while ( isBubbleOpen( bubbleIndex ) ) do
		coroutine.yield( ) ;
	end
	deleteBubble( bubbleIndex ) ;
end

function waitForBubbleOption( bubbleIndex )
	while ( isBubbleOpen( bubbleIndex ) ) do
		coroutine.yield( ) ;
	end
	local optionPressed = bubbleOptionPressed( bubbleIndex ) ;
	deleteBubble( bubbleIndex ) ;
	return optionPressed ;
end

function waitForBubbleDone( bubbleIndex )
	while ( not bubbleDone( bubbleIndex ) ) do
		coroutine.yield( ) ;
	end
end

function waitForTalk( initiatingCharacter, otherCharacter, allowChat )
	local waitingTalkNum = setWaitingForTalk( initiatingCharacter, otherCharacter, allowChat ) ;
	while ( not hasWaitingTalkOccured( waitingTalkNum ) ) do
		coroutine.yield( ) ;
	end
	setDoneWaitingTalk( waitingTalkNum ) ;
end

function waitForTalkTwo( initiatingCharacter, otherCharacter1, otherCharacter2, allowChat )
	local waitingTalkNum1 = setWaitingForTalk( initiatingCharacter, otherCharacter1, allowChat ) ;
	local waitingTalkNum2 = setWaitingForTalk( initiatingCharacter, otherCharacter2, allowChat ) ;
	while ( not hasWaitingTalkOccured( waitingTalkNum1 ) 
		and not hasWaitingTalkOccured( waitingTalkNum2 ) ) do
		coroutine.yield( ) ;
	end
	setDoneWaitingTalk( waitingTalkNum1 ) ;
	setDoneWaitingTalk( waitingTalkNum2 ) ;
end

function waitForTalkThree( initiatingCharacter, otherCharacter1, otherCharacter2, otherCharacter3, allowChat )
	local waitingTalkNum1 = setWaitingForTalk( initiatingCharacter, otherCharacter1, allowChat ) ;
	local waitingTalkNum2 = setWaitingForTalk( initiatingCharacter, otherCharacter2, allowChat ) ;
	local waitingTalkNum3 = setWaitingForTalk( initiatingCharacter, otherCharacter3, allowChat ) ;
	while ( not hasWaitingTalkOccured( waitingTalkNum1 ) 
		and not hasWaitingTalkOccured( waitingTalkNum2 )
		and not hasWaitingTalkOccured( waitingTalkNum3 ) ) do
		coroutine.yield( ) ;
	end
	setDoneWaitingTalk( waitingTalkNum1 ) ;
	setDoneWaitingTalk( waitingTalkNum2 ) ;
	setDoneWaitingTalk( waitingTalkNum3 ) ;
end

function waitForTalkFour( initiatingCharacter, otherCharacter1, otherCharacter2, otherCharacter3, otherCharacter4, allowChat )
	local waitingTalkNum1 = setWaitingForTalk( initiatingCharacter, otherCharacter1, allowChat ) ;
	local waitingTalkNum2 = setWaitingForTalk( initiatingCharacter, otherCharacter2, allowChat ) ;
	local waitingTalkNum3 = setWaitingForTalk( initiatingCharacter, otherCharacter3, allowChat ) ;
	local waitingTalkNum4 = setWaitingForTalk( initiatingCharacter, otherCharacter4, allowChat ) ;
	while ( not hasWaitingTalkOccured( waitingTalkNum1 ) 
		and not hasWaitingTalkOccured( waitingTalkNum2 )
		and not hasWaitingTalkOccured( waitingTalkNum3 )
		and not hasWaitingTalkOccured( waitingTalkNum4 ) ) do
		coroutine.yield( ) ;
	end
	setDoneWaitingTalk( waitingTalkNum1 ) ;
	setDoneWaitingTalk( waitingTalkNum2 ) ;
	setDoneWaitingTalk( waitingTalkNum3 ) ;
	setDoneWaitingTalk( waitingTalkNum4 ) ;
end

function chatBusy( name, chatWith )
	if ( isCharacterFighting( name ) ) then
		--autoDeleteFaceChat( name, chatWith, getFightText( name ) ) ;
		autoDeleteTimeFaceChat( name, chatWith, getFightText( name ) ) ;
		return true ;
	elseif ( characterHasGoal( name ) ) then
		-- nothing while walking
		return true ;
	end

	return false ; -- not busy
end

function isPlayerNude( )
	return ( not hasEquippedType( "pants" ) ) ;
end

function getGenericGreeting( friendlyness )
	local playerHonour = getCharacterHonour( "dartagnan" ) ;
	
	if ( isPlayerNude( ) ) then
		if ( friendlyness < 0.4 ) then
			return getString( "greetingnude1" ) ;
		elseif ( friendlyness < 0.75 ) then
			return getString( "greetingnude2" ) ;
		else
			return getString( "greetingnude3" ) ;
		end
	end
	
	local maxHonour = 60.0 ;
	local honourRatio = playerHonour / maxHonour ;
	
	local friendlynessWeight = 2.0 ;
	local honourWeight = 1.0 ;
	local totalWeight = friendlynessWeight + honourWeight ;
	
	local greetingRatio = ( friendlyness * friendlynessWeight + honourRatio * honourWeight ) / totalWeight ;
	if ( greetingRatio < 0.0 ) then
		greetingRatio = 0.0 ;
	elseif ( greetingRatio > 1.0 ) then
		greetingRatio = 1.0 ;
	end
	
	local totalGreetings = 14 ;
	local greetingNum = math.ceil( totalGreetings * greetingRatio ) ;
	if ( greetingNum <= 1 ) then
		greetingNum = 1 ;
	elseif ( greetingNum >= totalGreetings ) then
		greetingNum = totalGreetings ;
	end
	
	local greetingName = "greeting" .. string.format( "%i", greetingNum ) ;
	
	return getString( greetingName ) ;
end

function genericGreeting( name, chatWith, friendlyness )
	--autoDeleteFaceChat( name, chatWith, getGenericGreeting( friendlyness ) ) ;
	sayAndWait( name, getGenericGreeting( friendlyness ) ) ;
end

function getFameGreeting( )
	if ( isPlayerNude( ) ) then
		return getString( "famenude" ) ;
	end
		
	if ( isMissionComplete( "missionrochelle10" ) ) then
		return getString( "fame4" ) ;
	elseif ( isMissionComplete( "missionparis15" ) ) then
		return getString( "fame3" ) ;
	elseif ( isMissionComplete( "missionparis10" ) ) then
		return getString( "fame2" ) ;
	else
		return getString( "fame1" ) ;
	end
end

function fameGreeting( name, chatWith )
	--autoDeleteFaceChat( name, chatWith, getFameGreeting( ) ) ;
	sayAndWait( name, getFameGreeting( ) ) ;
end

function getGuardsmanGreeting( version )
	local commentNumber = 1 ;
	if ( isMissionComplete( "missionrochelle10" ) ) then
		commentNumber = 4 ;
	elseif ( isMissionComplete( "missionlondon10" ) ) then
		commentNumber = 3 ;
	elseif ( isMissionComplete( "missionparis15" ) ) then
		commentNumber = 2 ;
	else
		commentNumber = 1 ;
	end
	
	if ( isPlayerNude( ) ) then
		return getString( "guardsman" .. commentNumber .. "_" .. "nude" ) ;
	end
	
	if ( version < 1 ) then
		version = 1 ;
	elseif ( version > 3 ) then
		version = 3 ;
	end
	
	local greetingName = string.format( "guardsman%i_%i", commentNumber, version ) ;
	
	return getString( greetingName ) ;
end

function guardsmanGreeting( name, chatWith, version )
	--autoDeleteFaceChat( name, chatWith, getGuardsmanGreeting( version ) ) ;
	sayAndWait( name, getGuardsmanGreeting( version ) ) ;
end

function getCardGuardGreeting( version )
	local commentNumber = 1 ;
	if ( isMissionComplete( "missionrochelle10" ) ) then
		commentNumber = 4 ;
	elseif ( isMissionComplete( "missionlondon10" ) ) then
		commentNumber = 3 ;
	elseif ( isMissionComplete( "missionparis15" ) ) then
		commentNumber = 2 ;
	else
		commentNumber = 1 ;
	end
	
	if ( isPlayerNude( ) ) then
		return getString( "cardguard" .. commentNumber .. "_" .. "nude" ) ;
	end
	
	if ( version < 1 ) then
		version = 1 ;
	elseif ( version > 3 ) then
		version = 3 ;
	end
	
	local greetingName = string.format( "cardguard%i_%i", commentNumber, version ) ;
	
	return getString( greetingName ) ;
end

function cardGuardGreeting( name, chatWith, version )
	--autoDeleteFaceChat( name, chatWith, getCardGuardGreeting( version ) ) ;
	sayAndWait( name, getCardGuardGreeting( version ) ) ;
end

function waitUntilDead( charName )
	while ( isCharacterAlive( charName ) ) do
		coroutine.yield( ) ;
	end	
end

function getFightText( charName )
	local rn = randomInt( 0, 3 ) ;
	local text = "" ;
	if ( rn == 0 ) then
		text = getString( "fightchat_d1" ) ;
	elseif ( rn == 1 ) then
		text = getString( "fightchat_d2" ) ;
	else
		text = getString( "fightchat_d3" ) ;
	end

	return text ;
end

function getReviveText( charName )
	if ( charName == "athos" ) then
		return getString( "revivetext_1" ) ;
	elseif ( charName == "porthos" ) then
		return getString( "revivetext_2" ) ;
	elseif ( charName == "aramis" ) then
		return getString( "revivetext_3" ) ;
	else
		return getString( "revivetext_4" ) ;
	end
end

function reviveHelper3( char1, char2, char3, talkOnRecover )
	local healthAmount = 25 ;
	
	if ( ( not isCharacterAlive( char1 ) )
		or ( not isCharacterAlive( char2 ) )
		or ( not isCharacterAlive( char3 ) ) ) then
		-- someone is dead
		wait( 1.0 ) ;
	end
	
	if ( not isCharacterAlive( char1 ) ) then
		reviveCharacter( char1 ) ;
		giveHealth( char1, healthAmount ) ;
		--wait( 0.5 ) ;
		if ( talkOnRecover ) then
			--local bubInd = characterSay( char1, true, -1, 150.0, true, getReviveText( char1 ) ) ;
			--autoDeleteBubble( bubInd ) ;
			local bubInd = characterSay( char1, false, 6.0, BUBBLE_PROX_N, true, getReviveText( char1 ) ) ;
			autoDeleteBubble( bubInd ) ;
		end
		wait( 2 ) ;
	end
	
	if ( not isCharacterAlive( char2 ) ) then
		reviveCharacter( char2 ) ;
		giveHealth( char2, healthAmount ) ;
		--wait( 0.5 ) ;
		if ( talkOnRecover ) then
			--local bubInd = characterSay( char2, true, -1, 150.0, true, getReviveText( char2 ) ) ;
			--autoDeleteBubble( bubInd ) ;
			local bubInd = characterSay( char2, false, 6.0, BUBBLE_PROX_N, true, getReviveText( char2 ) ) ;
			autoDeleteBubble( bubInd ) ;
		end
		wait( 2 ) ;
	end
	
	if ( not isCharacterAlive( char3 ) ) then
		reviveCharacter( char3 ) ;
		giveHealth( char3, healthAmount ) ;
		--wait( 0.5 ) ;
		if ( talkOnRecover ) then
			--local bubInd = characterSay( char3, true, -1, 150.0, true, getReviveText( char3 ) ) ;
			--autoDeleteBubble( bubInd ) ;
			local bubInd = characterSay( char3, false, 6.0, BUBBLE_PROX_N, true, getReviveText( char3 ) ) ;
			autoDeleteBubble( bubInd ) ;
		end
		wait( 2 ) ;
	end
end

function reviveHelper4( char1, char2, char3, char4 )
	if ( ( not isCharacterAlive( char1 ) )
		or ( not isCharacterAlive( char2 ) )
		or ( not isCharacterAlive( char3 ) )
		or ( not isCharacterAlive( char4 ) ) ) then
		-- someone is dead
		wait( 1.0 ) ;
	end
	
	if ( not isCharacterAlive( char1 ) ) then
		reviveCharacter( char1 ) ;
		giveHealth( char1, 25 ) ;
		--wait( 0.5 ) ;
		--local bubInd = characterSay( char1, true, -1, 150.0, true, getReviveText( char1 ) ) ;
		--autoDeleteBubble( bubInd ) ;
		local bubInd = characterSay( char1, false, 6.0, BUBBLE_PROX_N, true, getReviveText( char1 ) ) ;
		autoDeleteBubble( bubInd ) ;
		wait( 2 ) ;
	end
	
	if ( not isCharacterAlive( char2 ) ) then
		reviveCharacter( char2 ) ;
		giveHealth( char2, 25 ) ;
		--wait( 0.5 ) ;
		--local bubInd = characterSay( char2, true, -1, 150.0, true, getReviveText( char2 ) ) ;
		--autoDeleteBubble( bubInd ) ;
		local bubInd = characterSay( char2, false, 6.0, BUBBLE_PROX_N, true, getReviveText( char2 ) ) ;
		autoDeleteBubble( bubInd ) ;
		wait( 2 ) ;
	end
	
	if ( not isCharacterAlive( char3 ) ) then
		reviveCharacter( char3 ) ;
		giveHealth( char3, 25 ) ;
		--wait( 0.5 ) ;
		--local bubInd = characterSay( char3, true, -1, 150.0, true, getReviveText( char3 ) ) ;
		--autoDeleteBubble( bubInd ) ;
		local bubInd = characterSay( char3, false, 6.0, BUBBLE_PROX_N, true, getReviveText( char3 ) ) ;
		autoDeleteBubble( bubInd ) ;
		wait( 2 ) ;
	end
	
	if ( not isCharacterAlive( char4 ) ) then
		reviveCharacter( char4 ) ;
		giveHealth( char4, 25 ) ;
		--wait( 0.5 ) ;
		--local bubInd = characterSay( char4, true, -1, 150.0, true, getReviveText( char4 ) ) ;
		--autoDeleteBubble( bubInd ) ;
		local bubInd = characterSay( char4, false, 6.0, BUBBLE_PROX_N, true, getReviveText( char4 ) ) ;
		autoDeleteBubble( bubInd ) ;
		wait( 2 ) ;
	end
end

function waitForNoActiveTutorialDialogue( )
	while ( hasActiveTutorialDialogue( ) ) do
		coroutine.yield( ) ;
	end
end

function waitForDidTutorialAllowedAction( )
	while ( not didTutorialAllowedAction( ) ) do
		coroutine.yield( ) ;
	end
end

function autoDeleteFaceChat( name, chatWith, text )
	local bubInd = characterSay( name, true, -1, BUBBLE_PROX_N, true, text ) ;
	setBubbleChatWith( bubInd, chatWith ) ;
	autoDeleteBubble( bubInd ) ;
end

function autoDeleteTimeFaceChat( name, chatWith, text )
	local bubInd = characterSay( name, false, 6.0, BUBBLE_PROX_N, true, text ) ;
	setBubbleChatWith( bubInd, chatWith ) ;
	autoDeleteBubble( bubInd ) ;
end

function autoDeleteChat( name, chatWith, text )
	local bubInd = characterSay( name, true, -1, BUBBLE_PROX_N, true, text ) ;
	autoDeleteBubble( bubInd ) ;
end

function sayAndWait( name, text )
	local bubInd = characterSay( name, true, -1, -1, true, text ) ;
	waitForBubbleClosed( bubInd ) ;
end

gAutoDeleteCharacters = {} ;

function autoDeleteCharacterOffScreen( name )
	table.insert( gAutoDeleteCharacters, name ) ;
	activateScriptMessage( "deleteCharacterOffScreen" ) ;
end

function deleteCharacterOffScreen( )
	local numberCharacters = table.getn( gAutoDeleteCharacters ) ;
	if ( numberCharacters > 0 ) then
		local name = gAutoDeleteCharacters[ numberCharacters ] ;
		table.remove( gAutoDeleteCharacters, numberCharacters ) ;

		table.foreach( gAutoDeleteCharacters, printiv ) ;
	
		while ( isCharacterOnScreen( name ) ) do
			coroutine.yield( ) ;
		end
	
		DEBUG_OUTPUT( "delete " .. name ) ;
		deleteTempCharacter( name ) ;
	end
end

function spinLook( character )
	-- only spin if not on horse
	if ( not characterIsDriving( character ) ) then
		local turnPeriod = 0.15 ;
		faceDirection( character, 1, 0 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, 1, 1 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, 0, 1 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, -1, 1 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, -1, 0 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, -1, -1 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, 0, -1 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, 1, -1 ) ;
		wait( turnPeriod ) ;
		faceDirection( character, 1, 0 ) ;
		wait( turnPeriod ) ;
	else
		wait( 1 ) ;
	end
end

function musksKnowDartagnan( )
	return isMissionComplete( "missionparis11" ) ;
end

function dartIsMusketeer( )
	return isMissionComplete( "missionrochelle10" ) ;
end

function chatDoctor( name, chatWith )
	if ( getRatioHealth( "dartagnan" ) < 0.99 ) then
		sayAndWait( name, getString( "doctor_d1" ) ) ;
		giveHealth( "dartagnan", 300 ) ;
	else
		--autoDeleteFaceChat( name, chatWith, getString( "doctor_d2" ) ) ;
		sayAndWait( name, getString( "doctor_d2" ) ) ;
	end
end

function oneLineChat( name, chatWith, text )
	sayAndWait( name, text ) ;
end

function dressNudeMan( name )
	clearCharacterPieces( name ) ;
	local skinR = 1.0 ;
	local skinG = 1.0 ;
	local skinB = 1.0 ;
	addCharacterPiece( name, "nm_head", skinR, skinG, skinB ) ;
	addCharacterPiece( name, "nm_hand_left", skinR, skinG, skinB ) ;
	addCharacterPiece( name, "nm_hand_right", skinR, skinG, skinB ) ;
	addCharacterPiece( name, "nm_arm_left", skinR, skinG, skinB ) ;
	addCharacterPiece( name, "nm_arm_right", skinR, skinG, skinB ) ;
	addCharacterPiece( name, "nm_leg_left", skinR, skinG, skinB ) ;
	addCharacterPiece( name, "nm_leg_right", skinR, skinG, skinB ) ;
	addCharacterPiece( name, "nm_torso", skinR, skinG, skinB ) ;
end

function dressNudeLady( name )
	clearCharacterPieces( name ) ;
	local skinR = 1.0 ;
	local skinG = 1.0 ;
	local skinB = 1.0 ;
	addCharacterPiece( name, "w_head", skinR, skinG, skinB  ) ;
	addCharacterPiece( name, "w_hand_left", skinR, skinG, skinB  ) ;
	addCharacterPiece( name, "w_hand_right", skinR, skinG, skinB  ) ;
	addCharacterPiece( name, "w_arm_left", skinR, skinG, skinB  ) ;
	addCharacterPiece( name, "w_arm_right", skinR, skinG, skinB  ) ;
	addCharacterPiece( name, "w_torso", skinR, skinG, skinB  ) ;
	addCharacterPiece( name, "w_dress_plain_legs" ) ;
end

--function deleteCharacterOffScreen( name )
--	while ( isCharacterOnScreen( name ) ) do
--		coroutine.yield( ) ;
--	end
--
--	DEBUG_OUTPUT( "delete " .. name ) ;
--	deleteTempCharacter( name ) ;
--end

function printiv( i, v )
	if ( ( type( v ) == "number" )
		or ( type( v ) == "string" ) ) then
		DEBUG_OUTPUT( i .. "=" .. v ) ;
	elseif ( type( v ) == "boolean" ) then
		-- can't concatenate boolean - so do it seperate
		local displayValue = "false" ;
		if ( v ) then
			displayValue = "true" ;
		end
		DEBUG_OUTPUT( i .. "=" .. displayValue ) ;
	end
end

function printAllGlobals( )
	DEBUG_OUTPUT( "\n---Globals Start---" ) ;
	table.foreach( _G, printiv ) ;
	DEBUG_OUTPUT( "---Globals End---\n" ) ;
end