//=============================================================================
// KFGameInfo_Tutorial
//=============================================================================
// The game mode class for a single player tutorial
//=============================================================================
// Killing Floor 2
// Copyright (C) 2016 Tripwire Interactive LLC
//=============================================================================

class KFGameInfo_Tutorial extends KFGameInfo_Survival
    dependson(KFTutorialSectionInfo)
    hidedropdown;

var class<KFGFxMoviePlayer_Tutorial>  MoviePlayerTutorialClass;
var KFGFxMoviePlayer_Tutorial         MyGFXTutorial;

var KFTutorialSectionInfo LobbyStartInfo;
var KFTutorialSectionInfo StartMatchInfo;
var KFTutorialSectionInfo Wave1EndInfo;
var KFTutorialSectionInfo TraderCloseInfo;
var KFTutorialSectionInfo VictoryInfo;
var KFTutorialSectionInfo HealSelfInfo;
var KFTutorialSectionInfo ZedTimeInfo;
var KFTutorialSectionInfo MeleeTutorial;

var KFTutorialSectionInfo TraderMenuTutorial;
var KFTutorialSectionInfo PerkMenuTutorial;
var KFTutorialSectionInfo GearMenuTutorial;
var KFTutorialSectionInfo InventoryMenuTutorial;
var KFTutorialSectionInfo StoreMenuTutorial;

var bool bShowedHealSelf;
var bool bShowedZedTime;
var bool bShowedTraderTutorial;
var bool bShowedMeleeTutorial;
var bool bShowedPerkMenuTutorial;
var bool bShowedGearMenuTutorial;
var bool bShowedInventoryMenuTutorial;
var bool bShowedStoreMenuTutorial;
var bool bShowedTraderCloseInfo;

/** Timer countdown (seconds) after player is done trading */
var int TimeAfterTrading;

/** Amount of dosh the player spawns with in the tutorial */
var int StartingDosh;

/** Cached local player controller ref */
var KFPlayerController MyPC;
/** Cached weapon for melee tutorial */
var Weapon CurrentWeapon;

event InitGame( string Options, out string ErrorMessage )
{
    // Force standalone for this game mode.  SetGameType() would be
    // ideal, but NetMode has no been set yet.
    if ( WorldInfo.NetMode != NM_Standalone )
    {
        ConsoleCommand("open" @ WorldInfo.GetMapName(true));
        return;
    }

    Super.InitGame(Options, ErrorMessage);
}

event PostBeginPlay()
{
    super.PostBeginPlay();

    // use defaultprops instead of difficulty sysstem
    TimeBetweenWaves = default.TimeBetweenWaves;
    `TraderDialogManager.bEnabled = false;
}

/** We're going to use our local PC often, so may as well cache it */
event PostLogin( PlayerController NewPlayer )
{
    Super.PostLogin(NewPlayer);

    // We're going to use our local PC often, so may as well cache it
    if ( NewPlayer.IsLocalController() )
    {
		MyPC = KFPlayerController(NewPlayer);
        CreateTutorialHUD(LobbyStartInfo);
    }
}

/** Override starting dosh */
function RestartPlayer(Controller NewPlayer)
{
    Super.RestartPlayer(NewPlayer);

    if( NewPlayer.PlayerReplicationInfo != None )
    {
        NewPlayer.PlayerReplicationInfo.Score = StartingDosh;
        CreateTutorialHUD(StartMatchInfo);
    }
}

/** 50% damage recieved */
function ReduceDamage(out int Damage, Pawn Injured, Controller InstigatedBy, vector HitLocation, out vector Momentum, class<DamageType> DamageType, Actor DamageCauser, TraceHitInfo HitInfo)
{
    if ( Injured.IsHumanControlled() )
    {
        //Damage = Max(Round(Damage / 2.f), 1);
        if(!bShowedHealSelf)
        {
            if(Injured.Health <= Injured.HealthMax * 0.90f)
            {
                CreateTutorialHUD(HealSelfInfo);
                bShowedHealSelf = true;
            }
        }
    }

    // checks neutral zone and god mode and calls mutator hook
    Super.ReduceDamage(Damage, Injured, InstigatedBy, HitLocation, Momentum, DamageType, DamageCauser, HitInfo);
}

function bool PreventDeath(Pawn KilledPawn, Controller Killer, class<DamageType> DamageType, vector HitLocation)
{
    if ( KilledPawn.IsHumanControlled() )
    {
        // give some bonus health so we're not always at 1 health
        KilledPawn.Health = KilledPawn.HealthMax * 0.25f;
        return true;
    }

    return Super.PreventDeath(KilledPawn, Killer, DamageType, HitLocation);
}

/**  */
function WaveEnded(EWaveEndCondition WinCondition)
{
    // Skip the final "dummy" wave and go to match ended
    if ( WaveNum == (WaveMax - 1) )
    {
        WaveNum = WaveMax;
    }

    Super.WaveEnded(WinCondition);
}

/**  */
function EndOfMatch(bool bVictory)
{
    Super.EndOfMatch(bVictory);

    if ( bVictory )
    {
		// Console builds try to claim tutorial rewards now
        //@SABER_EGS IsEosBuild() case added
		if( WorldInfo.IsConsoleBuild() || WorldInfo.IsEosBuild())
		{
			PlayfabInter.AddOnCloudScriptExecutionCompleteDelegate( OnTutorialRewardsComplete );
			PlayfabInter.ExecuteCloudScript( "ClaimTutorialRewards", none );
		}
        CreateTutorialHUD(VictoryInfo);
    }
}


function OnTutorialRewardsComplete( bool bWasSuccessful, string FunctionName, JsonObject FunctionResult )
{
	PlayfabInter.ClearOnCloudScriptExecutionCompleteDelegate( OnTutorialRewardsComplete );
	// On success, re-read inventory
	if( bWasSuccessful && FunctionName == "ClaimTutorialRewards" )
	{
		class'GameEngine'.static.GetPlayfabInterface().ReadInventory();
	}
}


/** Skip the AAR and return to main menu */
function ShowPostGameMenu()
{
    ConsoleCommand("disconnect");
}

/** Picks next trader index and allows for mutator hook */
function byte DetermineNextTraderIndex()
{
   local int index;
   local KFTraderTrigger Trader;

   // In evac there is a specific trader we want near some doors to weld
   ForEach TraderList(Trader, index)
   {
        if ( Trader.Name == 'KFTraderTrigger_17' )
        {
            return index;
        }
   }

   return super.DetermineNextTraderIndex();
}

/** No pickups introduced in the first round */
function ResetPickups( array<KFPickupFactory> PickupList, int NumPickups )
{
    if( WaveNum == 1 )
    {
        Super(KFGameInfo).ResetPickups(PickupList, 0);
    }

    super.ResetPickups( PickupList, NumPickups );
}

function SetZedTimeDilation(float NewTimeDilation)
{
    super.SetZedTimeDilation(NewTimeDilation);
    if(NewTimeDilation == ZedTimeSlomoScale)   
    {
        if(!bShowedZedTime)
        {
            CreateTutorialHUD(ZedTimeInfo);
            bShowedZedTime = true;
        }
    }
}

/** check main menu tutorial(s) */
function NotifyMenuOpened(byte MenuIndex)
{        
    switch(MenuIndex)
    {
        case UI_Perks:
            if ( !bShowedPerkMenuTutorial )
            {
                CreateTutorialHUD(PerkMenuTutorial);
                bShowedPerkMenuTutorial = true;
                return;
            }
            break;

        case UI_Gear:
            if ( !bShowedGearMenuTutorial )
            {
                CreateTutorialHUD(GearMenuTutorial);
                bShowedGearMenuTutorial = true;
                return;
            }
            break;
        case UI_Inventory:
            if ( !bShowedInventoryMenuTutorial )
            {
                CreateTutorialHUD(InventoryMenuTutorial);
                bShowedInventoryMenuTutorial = true;
                return;
            }
            break;
        case UI_Store:
            if ( !bShowedStoreMenuTutorial )
            {
                CreateTutorialHUD(StoreMenuTutorial);
                bShowedStoreMenuTutorial = true;
                return;
            }
            break;
    }
}

/*********************************************************************************************
 * KFGFxMoviePlayer_Tutorial Interface
 *********************************************************************************************/

function bool AllowUnpause()
{
    if(MyGFXTutorial != none)
    {
        return false;
    }
    
    return true;
}

/** Create/Open a tutorial popup */
function CreateTutorialHUD(KFTutorialSectionInfo TutorialSectionInfo, optional bool bViaTimer)
{
    local PlayerController PC;

    // If we asked for a tutorial that requires a delay do that now.  Track
    // on the tutorial object so we can have multiple simultaneous timers
    if ( !bViaTimer && TutorialSectionInfo.OpenDelay > 0 )
    {
        SetTimer(TutorialSectionInfo.OpenDelay, false, nameof(TutorialSectionInfo.OpenDelayTimer), TutorialSectionInfo);
        return;
    }

    PC = GetALocalPlayerController();

    PC.PlayerInput.ResetInput();

    // @todo: object creation should only be done once?
    if(MyGFXTutorial == none && MoviePlayerTutorialClass != None )
    {
        MyGFXTutorial = new MoviePlayerTutorialClass;        
        MyGFXTutorial.SetTimingMode(TM_Real);
        MyGFXTutorial.TutorialSectionInfo = TutorialSectionInfo;
        MyGFXTutorial.TargetTutorialArray = TutorialSectionInfo.GetSlides(PC);
    }
    
    if(PC != none && MyGFXTutorial != none)
    {        
        MyGFXTutorial.Init(class'Engine'.static.GetEngine().GamePlayers[MyGFXTutorial.LocalPlayerOwnerIndex]);
        PC.SetPause(true, AllowUnpause);     
        if(MyGFXTutorial.TutorialSectionInfo.VoiceOverOpenEvent != none)
        {
            PC.PlaySoundBase( MyGFXTutorial.TutorialSectionInfo.VoiceOverOpenEvent, true, false, false );   
        }
    }
}

/** Close, unpause, and delete the tutorial UI object **/
function RemoveTutorialHud()
{
    local PlayerController PC;

    if ( MyGFXTutorial != None )
    {
        PC = GetALocalPlayerController();
        if(PC != none)
        {
            if(MyGFXTutorial.TutorialSectionInfo.VoiceOverOpenEvent != none)
            {
                PC.PlaySoundBase( MyGFXTutorial.TutorialSectionInfo.VoiceOverCloseEvent, true, false, false );   
            }
            MyGFXTutorial.Close(true);
            MyGFXTutorial = None;
            PC.SetPause(false);
        }
    }
}


function NotifyControllerDisconnected()
{
	if( MyGFXTutorial != none )
	{
		MyGFXTutorial.SetVisibility( false );
		// Make tutorial hide if we need to show controller disconnect dialog
		MyGFXTutorial.SetPriority(1);
		KFPlayerController(GetALocalPlayerController()).MyGFxManager.SetPriority(2);
	}
}


function NotifyControllerReconnected()
{
	if (MyGFXTutorial != none)
	{
		MyGFXTutorial.SetVisibility( true );
		// Put tutorial back on top
		MyGFXTutorial.SetPriority(2);
		KFPlayerController(GetALocalPlayerController()).MyGFxManager.SetPriority(1);
	}
}


/*********************************************************************************************
 * Update
 *********************************************************************************************/

function Tick( float DeltaTime )
{
    Super.Tick(DeltaTime);

    // Normally we wouldn't use a script tick for something like this, but in this
    // case it's a little cleaner using the brute force approach and this is not
    // a performance critical class.
    CheckPlayerAction();
}

/** Brute force update for what a player has done recently so we can display tutorials */
function CheckPlayerAction()
{
    // check melee tutorial
    if ( !bShowedMeleeTutorial && MyPC.Pawn != None && CurrentWeapon != MyPC.Pawn.Weapon )
    {
        if ( MyPC.Pawn.Weapon.IsA('KFWeap_MeleeBase') )
        {
            CreateTutorialHUD(MeleeTutorial);
            bShowedMeleeTutorial = true;
        }
        CurrentWeapon = MyPC.Pawn.Weapon;
    }
}

/*********************************************************************************************
 * state TraderOpen
 *********************************************************************************************/

State TraderOpen
{   
    function BeginState( Name PreviousStateName )
    {
        super.BeginState(PreviousStateName);
        CreateTutorialHUD(Wave1EndInfo);
    }

    // Normally we would use Timer(), but perf is not an issue here
    function CheckPlayerAction()
    {
        // Notify when menu is closed.  Menu wil be 'None' before it's been opened for the first time
        if ( MyKFGRI.RemainingTime > TimeAfterTrading )
        {           
            if ( MyPC != None && MyPC.MyGFxManager.TraderMenu != None )
            {
                if ( !MyPC.bClientTraderMenuOpen )
                {
                    OnTraderMenuClosed();
                    return;
                }
                else if ( !bShowedTraderTutorial )
                {
                    CreateTutorialHUD(TraderMenuTutorial);
                    bShowedTraderTutorial = true;
                    return;
                }
                else
                {
                    MyKFGRI.RemainingTime = TimeBetweenWaves;
                    MyKFGRI.RemainingMinute = TimeBetweenWaves;
                }
            }
        }

        if( MyPC.bClientTraderMenuOpen )
        {
            MyKFGRI.RemainingTime = TimeBetweenWaves;
            MyKFGRI.RemainingMinute = TimeBetweenWaves;
            ClearTimer(nameof(CloseTraderTimer));
        }

        Global.CheckPlayerAction();
    }
}

function OnTraderMenuClosed()
{
    // shorten time remaining before next wave
    if ( MyKFGRI.RemainingTime > TimeAfterTrading )
    {
        MyKFGRI.RemainingTime = TimeAfterTrading;
        MyKFGRI.RemainingMinute = TimeAfterTrading;

		if( !bShowedTraderCloseInfo )
        {
            CreateTutorialHUD(TraderCloseInfo);
            bShowedTraderCloseInfo = true;
        }

        // refresh timer
        SetTimer(TimeAfterTrading, false, nameof(CloseTraderTimer));
    }
}

function bool IsMapObjectiveEnabled()
{
	return false;
}

DefaultProperties
{
    StartMatchInfo=KFTutorialSectionInfo'GP_Tutorial_ARCH.StartMatchArch'
    Wave1EndInfo=KFTutorialSectionInfo'GP_Tutorial_ARCH.Wave1EndArch'    
    TraderCloseInfo=KFTutorialSectionInfo'GP_Tutorial_ARCH.TraderCloseArch'
    VictoryInfo=KFTutorialSectionInfo'GP_Tutorial_ARCH.VictoryArch'
    HealSelfInfo=KFTutorialSectionInfo'GP_Tutorial_ARCH.HealSelfArch'
    ZedTimeInfo=KFTutorialSectionInfo'GP_Tutorial_ARCH.ZedTimeArch'
    LobbyStartInfo=KFTutorialSectionInfo'GP_Tutorial_ARCH.LobbyStartArch'
    MeleeTutorial=KFTutorialSectionInfo'GP_Tutorial_ARCH.MeleeArch'

    PerkMenuTutorial=KFTutorialSectionInfo'GP_Tutorial_ARCH.PerkMenuArch'
    GearMenuTutorial=KFTutorialSectionInfo'GP_Tutorial_ARCH.GearMenuArch'
    InventoryMenuTutorial=KFTutorialSectionInfo'GP_Tutorial_ARCH.InventoryMenuArch'
    StoreMenuTutorial=KFTutorialSectionInfo'GP_Tutorial_ARCH.StoreMenuArch'
    TraderMenuTutorial=KFTutorialSectionInfo'GP_Tutorial_ARCH.TraderOpenArch'

    // tutorial subclass to catch player menu navigation
    KFGFxManagerClass=class'KFGFxMoviePlayer_Manager_Tutorial'

    MoviePlayerTutorialClass =Class'KFGFxMoviePlayer_Tutorial'
    MaxGameDifficulty=0
    SpawnManagerClasses.Empty
	SpawnManagerClasses(0)=class'KFAISpawnManager_Tutorial'

    TimeBetweenWaves=600
    TimeAfterTrading=30
    StartingDosh=2000
}