// made to fix KFStoryGameInfo loading for KFO maps
class NiceGameType extends ScrnGameType;

var NicePack NicePackMutator;
var bool lessDramatic;
var float LesserZedTimeSlomoScale;
var ZedTimeComponent zedTimeHandler;

function RegisterMutator(NicePack activePack){
    NicePackMutator = activePack;
}
function OverrideMonsterHealth(KFMonster M){}
/*event InitGame(string Options, out string Error){
    local int i, j;
    if(ScrnGameLength == none)
       ScrnGameLength = new(none, string(KFGameLength)) class'ScrnGameLength';
    for(i = 0;i < ScrnGameLength.
}*/
function int SpawnSquad(ZombieVolume ZVol, out array< class<KFMonster> > Squad, optional bool bLogSpawned ){
    local int i, j;
    local array<NicePack.ZedRecord> zedDatabase;
    if(NicePackMutator != none){
       zedDatabase = NicePackMutator.zedDatabase;
       for(i = 0;i < zedDatabase.Length;i ++){
           for(j = 0;j < Squad.Length;j ++){
               if(zedDatabase[i].bNeedsReplacement && zedDatabase[i].ZedType == Squad[j])
                   Squad[j] = zeddatabase[i].MeanZedType;
           }
       }
    }
    return super.SpawnSquad(ZVol, Squad, bLogSpawned);
}
function SetupWave(){
    Super.SetupWave();
    // Event call
    NicePackMutator.WaveStart();
}
function RestartPlayer(Controller aPlayer){
    Super.RestartPlayer(aPlayer);
    if(aPlayer.Pawn != none && NicePlayerController(aPlayer) != none)
       NicePlayerController(aPlayer).PawnSpawned();
}
State MatchInProgress{
    function BeginState(){
       Super(Invasion).BeginState();

       WaveNum = InitialWave;
       InvasionGameReplicationInfo(GameReplicationInfo).WaveNumber = WaveNum;

       if(NicePackMutator.bInitialTrader) {
           WaveCountDown = NicePackMutator.initialTraderTime + 5;
           NicePackMutator.TraderStart();
       }
       else
           WaveCountDown = 10;

       SetupPickups();
       if(ScrnGameLength != none && !ScrnGameLength.LoadWave(WaveNum))
           DoWaveEnd();

       // Event call
       NicePackMutator.MatchBegan();
    }
    function DoWaveEnd(){
       Super.DoWaveEnd();
       // Event call
       NicePackMutator.TraderStart();
    }
    function StartWaveBoss(){
       Super.StartWaveBoss();
       // Event call
       NicePackMutator.WaveStart();
    }
}

function ScoreKill(Controller Killer, Controller Other)
{
    local NicePlayerController niceKiller;
    local NiceHumanPawn niceKillerPawn;
    local PlayerReplicationInfo OtherPRI;
    local float KillScore;
    local Controller C;

    OtherPRI = Other.PlayerReplicationInfo;
    if ( OtherPRI != none )
    {
        OtherPRI.NumLives++;
        OtherPRI.Score -= (OtherPRI.Score * (GameDifficulty * 0.05));   // you Lose 35% of your current cash on Hell on Earth, 15% on normal.
        OtherPRI.Team.Score -= (OtherPRI.Score * (GameDifficulty * 0.05));

        if (OtherPRI.Score < 0 )
            OtherPRI.Score = 0;
        if (OtherPRI.Team.Score < 0 )
            OtherPRI.Team.Score = 0;

        OtherPRI.Team.NetUpdateTime = Level.TimeSeconds - 1;
        OtherPRI.bOutOfLives = true;
        if( Killer!=none && Killer.PlayerReplicationInfo!=none && Killer.bIsPlayer )
            BroadcastLocalizedMessage(class'KFInvasionMessage',1,OtherPRI,Killer.PlayerReplicationInfo);
        else if( Killer==none || Monster(Killer.Pawn)==none )
            BroadcastLocalizedMessage(class'KFInvasionMessage',1,OtherPRI);
        else BroadcastLocalizedMessage(class'KFInvasionMessage',1,OtherPRI,,Killer.Pawn.Class);
        CheckScore(none);
    }

    if ( GameRulesModifiers != none )
        GameRulesModifiers.ScoreKill(Killer, Other);

    if ( MonsterController(Killer) != none )
        return;

    if( (killer == Other) || (killer == none) )
    {
        if ( Other.PlayerReplicationInfo != none )
        {
            Other.PlayerReplicationInfo.Score -= 1;
            Other.PlayerReplicationInfo.NetUpdateTime = Level.TimeSeconds - 1;
            ScoreEvent(Other.PlayerReplicationInfo,-1,"self_frag");
        }
    }

    if ( Killer==none || !Killer.bIsPlayer || (Killer==Other) )
        return;

    if ( Other.bIsPlayer )
    {
        Killer.PlayerReplicationInfo.Score -= 5;
        Killer.PlayerReplicationInfo.Team.Score -= 2;
        Killer.PlayerReplicationInfo.NetUpdateTime = Level.TimeSeconds - 1;
        Killer.PlayerReplicationInfo.Team.NetUpdateTime = Level.TimeSeconds - 1;
        ScoreEvent(Killer.PlayerReplicationInfo, -5, "team_frag");
        return;
    }
    if ( LastKilledMonsterClass == none )
        KillScore = 1;
    else if(Killer.PlayerReplicationInfo !=none)
    {
        KillScore = LastKilledMonsterClass.Default.ScoringValue;

        // Scale killscore by difficulty
        if ( GameDifficulty >= 5.0 ) // Suicidal and Hell on Earth
        {
            KillScore *= 0.65;
        }
        else if ( GameDifficulty >= 4.0 ) // Hard
        {
            KillScore *= 0.85;
        }
        else if ( GameDifficulty >= 2.0 ) // Normal
        {
            KillScore *= 1.0;
        }
        else //if ( GameDifficulty == 1.0 ) // Beginner
        {
            KillScore *= 2.0;
        }

        // Increase score in a short game, so the player can afford to buy cool stuff by the end
        if( KFGameLength == GL_Short )
        {
            KillScore *= 1.75;
        }

        KillScore = Max(1,int(KillScore));
        if (NicePackMutator.bUseProgresiveCash) {
            KillScore = 0;
        }
        Killer.PlayerReplicationInfo.Kills++;

        ScoreKillAssists(KillScore, Other, Killer);

        Killer.PlayerReplicationInfo.Team.Score += KillScore;
        Killer.PlayerReplicationInfo.NetUpdateTime = Level.TimeSeconds - 1;
        Killer.PlayerReplicationInfo.Team.NetUpdateTime = Level.TimeSeconds - 1;
        TeamScoreEvent(Killer.PlayerReplicationInfo.Team.TeamIndex, 1, "tdm_frag");
    }

    if (Killer.PlayerReplicationInfo !=none && Killer.PlayerReplicationInfo.Score < 0)
        Killer.PlayerReplicationInfo.Score = 0;


    /* Begin Marco's Kill Messages */

        if( Class'HUDKillingFloor'.Default.MessageHealthLimit<=Other.Pawn.Default.Health ||
        Class'HUDKillingFloor'.Default.MessageMassLimit<=Other.Pawn.Default.Mass )
        {
            for( C=Level.ControllerList; C!=none; C=C.nextController )
            {
                if( C.bIsPlayer && xPlayer(C)!=none )
                {
                    xPlayer(C).ReceiveLocalizedMessage(Class'KillsMessage',1,Killer.PlayerReplicationInfo,,Other.Pawn.Class);
                }
            }
        }
        else
        {
            if( xPlayer(Killer)!=none )
            {
                xPlayer(Killer).ReceiveLocalizedMessage(Class'KillsMessage',,,,Other.Pawn.Class);
            }
        }

    /* End Marco's Kill Messages */
    niceKiller = NicePlayerController(killer);
    if (niceKiller != none && niceKiller.abilityManager != none) {
        niceKillerPawn = NiceHumanPawn(niceKiller.pawn);
        niceKiller.abilityManager.AddToAllCooldowns(-1);
    }
    if (    niceKillerPawn != none && NiceBoomStick(niceKillerPawn.weapon) != none
        &&  other != none && other.pawn != none && other.pawn.default.health >= 1000) {
        niceKillerPawn.invincibilityTimer += 1.0;
    }
}

function DramaticEvent(float BaseZedTimePossibility, optional float DesiredZedTimeDuration){
    local bool bWasZedTime;
    bWasZedTime = bZEDTimeActive;
    if (lessDramatic)
    {
        if (bZEDTimeActive) {
            return;
        }
        else {
            ZedTimeSlomoScale = LesserZedTimeSlomoScale;
        }
    }
    Super.DramaticEvent(BaseZedTimePossibility, DesiredZedTimeDuration);
    ZedTimeSlomoScale = default.ZedTimeSlomoScale;
    // Call event
    if(!bWasZedTime && bZEDTimeActive)
       NicePackMutator.ZedTimeActivated();
}

event Tick(float DeltaTime){
    if (zedTimeHandler == none) {
        zedTimeHandler = new() class'ZedTimeComponent';
    }
    zedTimeHandler.ProcessTick(deltaTime / level.timeDilation);
}

function Killed(Controller Killer, Controller Killed, Pawn KilledPawn, class<DamageType> dmgType){
    local GameRules rules;
    local NicePlayerController nicePlayer;
    local NiceAvoidMarkerCarnage AvoidArea;
    local ScrnGameRules scrnRules;
    local KFSteamStatsAndAchievements StatsAndAchievements;
    Super.Killed(Killer, Killed, KilledPawn, dmgType);
    if(PlayerController(Killer) != none){
        nicePlayer = NicePlayerController(killer);
       if(NiceMonster(KilledPawn) != none && Killed != Killer){
            //   Brutal carnage
            if (nicePlayer != none && killer.pawn != none && nicePlayer.abilityManager != none && nicePlayer.abilityManager.IsAbilityActive("carnage"))
            {
                AvoidArea = Spawn(class'NiceAvoidMarkerCarnage', killer.pawn);
                AvoidArea.SetLocation(KilledPawn.location);
                AvoidArea.healthLevel = killedPawn.default.health;
                AvoidArea.SetCollisionSize( class'NiceSkillEnforcerBrutalCarnageA'.default.avoidRadius,
                                            class'NiceSkillEnforcerBrutalCarnageA'.default.avoidRadius);
                AvoidArea.StartleBots();
            }
            //   Rest
            StatsAndAchievements = KFSteamStatsAndAchievements(PlayerController(Killer).SteamStatsAndAchievements);
            if(StatsAndAchievements != none){
                if(KilledPawn.IsA('NiceZombieStalker') || KilledPawn.IsA('MeanZombieStalker')){
                    if(class<NiceDamTypeWinchester>(dmgType) != none)
                        StatsAndAchievements.AddStalkerKillWithLAR();
                }
                else if(KilledPawn.IsA('NiceZombieClot') || KilledPawn.IsA('MeanZombieClot')){
                    if(class<NiceDamTypeWinchester>(dmgType) != none)
                        KFSteamStatsAndAchievements(PlayerController(Killer).SteamStatsAndAchievements).AddClotKillWithLAR();
                }
                if(class<NiceWeaponDamageType>(dmgType) != none){
                    for(rules = Level.Game.GameRulesModifiers;rules != none;rules = rules.NextGameRules)
                        if(ScrnGameRules(rules) != none){
                            scrnRules = ScrnGameRules(rules);
                            break;
                        }
                    if(scrnRules != none)
                        class<NiceWeaponDamageType>(dmgType).Static.AwardNiceKill(StatsAndAchievements, KFPlayerController(Killer), KFMonster(KilledPawn), scrnRules.HardcoreLevel);
                }
            }
       }
    }
}
// Reloaded to award damage
function int ReduceDamage(int Damage, pawn injured, pawn instigatedBy, vector HitLocation, out vector Momentum, class<DamageType> DamageType){
    local NiceMonster niceZed;
    local KFPlayerController PC;
    niceZed = NiceMonster(Injured);
    if(niceZed != none){
       if(instigatedBy != none){
           PC = KFPlayerController(instigatedBy.Controller);
           if(class<NiceWeaponDamageType>(damageType) != none && PC != none)
               class<NiceWeaponDamageType>(damageType).Static.AwardNiceDamage(KFSteamStatsAndAchievements(PC.SteamStatsAndAchievements), Clamp(Damage, 1, Injured.Health), niceZed.scrnRules.HardcoreLevel);
       }
    }
    return Super.ReduceDamage(Damage, injured, InstigatedBy, HitLocation, Momentum, DamageType);
}

// HINTS: override to make fancy loading creen hints
static function string GetLoadingHint(PlayerController pc, string MapName, Color ColorHint)
{
    // call super code just to draw the map icon and description
    super.GetLoadingHint(pc, MapName, ColorHint);
    // return colored and custom HINTS
    return class'Utility'.static.GetNiceHint();
}

// HINTS: override to make fancy ingame menu hints
static function array<string> GetAllLoadHints(optional bool bThisClassOnly)
{
    return class'Utility'.static.GetNiceHintArray();
}

defaultproperties
{
    GameName="Nice Floor"
    Description="Nice Edition of ScrN Killing Floor game mode (ScrnGameType)."
    // custom player controller
    PlayerControllerClass=class'NicePlayerController'
    PlayerControllerClassName="NicePack.NicePlayerController"
    // skills menu
    LoginMenuClass="NicePack.NiceInvasionLoginMenu"
    ZedTimeSlomoScale=0.4
    LesserZedTimeSlomoScale=0.6
}