class HideMutInteraction extends Interaction
  config(HideMut);


// N.B. Important references
// don't forget to null them on map switch !!
var KFPlayerController pc;
var a_CharFix a_CharFix;
var a_CashTosser a_CashTosser;
var a_WeaponTosser a_WeaponTosser;
var a_WeaponManager a_weaponManager;
var a_VisibilityHandler a_visibilityHandler;

var bool bBuyMode;
var bool bCP;
var bool bReveal;
var bool bInitialized;

// crosshair shit
var config float XLength, XWidth;
var config Color CrosshairColor;
var config bool bCross;

// zed health bar related
var transient bool bHPBar;
var config float fHPBar;

// lighting related
var Halo HaloLight;
var transient bool bHalo;

var class<KFVoicePack> VoiceClass;

//=============================================================================
//                           CLEANUP
//=============================================================================

event NotifyLevelChange()
{
  local KFConsole console;

  // remove our references or we will crash eventually
  pc = none;
  VoiceClass = none;

  // so we can catch our spawn time
  bInitialized = false;

  // start the tick
  bRequiresTick = true;

  // get the console and clean the level
  // this should not crash and free some memory
  console = KFConsole(viewportOwner.console);
  if (console != none)
  {
    console.DelayedConsoleCommand("obj garbage");
    console.DelayedConsoleCommand("flush");
    // cleans the console
    console.DelayedConsoleCommand("cls");
  }

  if (a_weaponManager != none)
  {
    a_weaponManager.destroy();
    a_weaponManager = none;
  }
  if (a_WeaponTosser != none)
  {
    a_WeaponTosser.destroy();
    a_WeaponTosser = none;
  }
  if (a_CashTosser != none)
  {
    a_CashTosser.destroy();
    a_CashTosser = none;
  }
  if (a_visibilityHandler != none)
  {
    a_visibilityHandler.destroy();
    a_visibilityHandler = none;
  }
  if (a_CharFix != none)
  {
    a_CharFix.destroy();
    a_CharFix = none;
  }
  a_CharFix = viewportOwner.actor.spawn(class'a_CharFix');
}


//=============================================================================
//                           FAST-ACCESS FUNCTIONS
//=============================================================================

simulated function KFHumanPawn getPawn()
{
  return KFHumanPawn(KFPlayerController(viewportOwner.actor).pawn);
}


simulated function KFPlayerController getController()
{
  return KFPlayerController(viewportOwner.actor);
}


simulated function bool getPC(out KFPlayerController pc)
{
  if (KFPlayerController(viewportOwner.actor) != none)
    pc = KFPlayerController(viewportOwner.actor);
  return (pc != none);
}


simulated function bool isPlayerAlive()
{
  getPC(pc);

  if (pc == none || pc.isInState('Spectating') || pc.isInState('Dead') || pc.isInState('PlayerWaiting') || pc.isInState('WaitingForPawn'))
    return false;
  return true;
}


simulated function checkVisibilityHandler()
{
  if (a_visibilityHandler == none)
    a_visibilityHandler = getController().spawn(class'a_VisibilityHandler', getController());
}


simulated function msg(string message)
{
  if (getController() != none)
    getController().myHUD.AddTextMessage(message, class'LocalMessage', getController().playerReplicationInfo);
}


//=============================================================================
//                                   MENUS
//=============================================================================

exec simulated function hideMenu()
{
  GUIController(viewportOwner.guiController).openMenu("HideMut.NewMenu");
}


exec simulated function hideMenuOld()
{
  GUIController(viewportOwner.guiController).openMenu("HideMut.HideMutMenuOld");
}


exec simulated function hideMenuNew()
{
  checkVisibilityHandler(); // TODO: do I need it here?
  GUIController(viewportOwner.guiController).openMenu("HideMut.HideMenu");
}


exec simulated function weaponManagement()
{
  GUIController(viewportOwner.guiController).openMenu("HideMut.WeaponManagerMenu");
}


//=============================================================================
//                                 CRASHING n Nades
//=============================================================================

// requires at least 2-3k dosh
exec simulated function crashServer()
{
  class'u_CrashTool'.static.doshspam(getPawn());
}


// nade technic
exec simulated function crashServer2()
{
  class'u_CrashTool'.static.nadespam(getPawn(), 100);
}


// spec - join technic
exec simulated function crashServer3()
{
  class'u_CrashTool'.static.specspam(getController());
}


// infinite nades for vanilla
exec simulated function nade()
{
  class'u_CrashTool'.static.ThrowNade(getPawn());
}


// infinite nades for vanilla
exec simulated function bignade(int i)
{
  class'u_CrashTool'.static.nadespam(getPawn(), i);
}


//=============================================================================
//                                 Trader
//=============================================================================

// Buys vest
exec simulated function buyKevlar()
{
  getPawn().serverBuyKevlar();
}


// Restores HP (Constant 150£)
exec simulated function buyHP()
{
  getPawn().serverBuyFirstAid();
}


// Buys ammo for all weapons
exec simulated function buyAmmo()
{
  local KFHumanPawn me;
  local Inventory inv;

  me = getPawn();

  if (me != none)
  {
    for(inv = me.inventory; inv != none; inv = inv.inventory)
    {
      if (inv != none)
      {
        if (KFWeapon(inv) != none)
        {
          if (Weapon(inv).ammoClass[0]!= none)
            me.serverBuyAmmo(Weapon(inv).ammoClass[0], false);
          if (Weapon(inv).AmmoClass[1]!= none)
            me.serverBuyAmmo(Weapon(inv).ammoClass[1], false);
        }
      }
    }
  }
}


// Allows to buy any weapon with its class name
exec simulated function buy(string weaponClassName)
{
  local class<KFWeapon> weaponToBuy;

  weaponToBuy = class<KFWeapon>(dynamicLoadObject(weaponClassName, class'Class', true));
  getPawn().serverBuyWeapon(weaponToBuy, 0);
}


// Buys all vanilla weapons
exec simulated function buyAll()
{
  local int i;
  local KFHumanPawn me;
  local array<class <KFWeapon> > Weapons;

  getPC(pc);
  Weapons = class'u_WeaponHelper'.static.getALLWeapons(pc);
  me = getPawn();

  for(i = 0; i < Weapons.length; i++)
  {
    me.serverBuyWeapon(Weapons[i],0);
  }

  // msg("You've just bought every single weapon in KF, you sick bastard.");
}


// unlocks all DLC weapons
// requires modified Engine.u
exec simulated function unlockDlc()
{
  getController().serverInitializeSteamStatInt(200, 4095);
  KFSteamStatsAndAchievements(getController().steamStatsAndAchievements).ownedWeaponDLC.value = 4095;
  msg("All DLCs were unlocked.");
}


//=============================================================================
//                            WEAPON MANAGEMENT
//=============================================================================

// just checks if everything is alright
simulated function weaponManagerCheck()
{
  if (a_weaponManager == none)
  {
    a_weaponManager = getController().spawn(class'a_WeaponManager');
    a_weaponManager.kfpc = getController();
  }
  if (a_weaponManager.kfpc != getController())
    a_weaponManager.kfpc = getController();

  if (getPawn().weapon == none)
    getController().switchToBestWeapon();
}


exec simulated function reallyQuickHeal()
{
  weaponManagerCheck();
  a_weaponManager.reallyQuickHeal();
}


simulated function ParseWeaponManagerSlots(int i)
{
  weaponManagerCheck();
  if (a_weaponManager.bUseVanillaManagement)
  {
    getController().switchWeapon(i);
    return;
  }

  a_weaponManager.getWeapon(i);
}


exec simulated function getWeapon1()
{
  ParseWeaponManagerSlots(1);
}


exec simulated function getWeapon2()
{
  ParseWeaponManagerSlots(2);
}


exec simulated function getWeapon3()
{
  ParseWeaponManagerSlots(3);
}


exec simulated function getWeapon4()
{
  ParseWeaponManagerSlots(4);
}


exec simulated function getWeapon5()
{
  ParseWeaponManagerSlots(5);
}


exec simulated function getWeapon6()
{
  ParseWeaponManagerSlots(6);
}


exec simulated function getWeapon7()
{
  ParseWeaponManagerSlots(7);
}


exec simulated function getWeapon8()
{
  ParseWeaponManagerSlots(8);
}


exec simulated function getWeapon9()
{
  ParseWeaponManagerSlots(9);
}


//=============================================================================
//                              WEAPON FUNCTIONS
//=============================================================================

exec simulated function showPriority()
{
  msg(string(getPawn().weapon.default.priority));
}


// fast shooting
exec simulated function nonStop(optional bool bNewWaitForRelease, optional bool bAllWeapons)
{
  local Inventory Inv;
  local KFHumanPawn me;
  local KFWeapon kfw;

  me = getPawn();
  if (!bAllWeapons)
  {
    kfw = KFWeapon(me.weapon);
    if (kfw != none)
      kfw.serverChangeFireMode(bNewWaitForRelease);
  }
  else
  {
    for(Inv = me.Inventory; Inv != none; Inv = Inv.Inventory)
    {
      kfw = KFWeapon(Inv);
      if (kfw != none && kfw.bConsumesPhysicalAmmo && !kfw.bMeleeWeapon)
        kfw.serverChangeFireMode(bNewWaitForRelease);
    }
  }

  // KFHumanPawn(KFPlayerController(viewportOwner.actor).pawn);
  // KFWeapon(KFHumanPawn(getController().pawn).weapon).serverChangeFireMode(bNewWaitForRelease);
  // KFWeapon(KFHumanPawn(getController().pawn).weapon).fireMode[0].bWaitForRelease = bNewWaitForRelease;
}


// no recoil
exec simulated function nr()
{
  local WeaponFire wf;
  local KFFire kff;
  local KFShotgunFire kfsf;

  forEach allObjects(class'WeaponFire', wf)
  {
    if (wf == none)
      continue;

    kff = KFFire(wf);
    if (kff != none)
    {
      kff.RecoilRate = 0.0;
      kff.maxVerticalRecoilAngle = 0;
      kff.maxHorizontalRecoilAngle = 0;
    }

    kfsf = KFShotgunFire(wf);
    if (kfsf != none)
    {
      kfsf.RecoilRate = 0.0;
      kfsf.maxVerticalRecoilAngle = 0;
      kfsf.maxHorizontalRecoilAngle = 0;
    }

    // kfsf.RandomPitchAdjustAmt = 0;
    // kfsf.Spread = 0;
    // kfsf.SpreadStyle=SS_None;
    // kfsf.FireRate=20;
    // kfsf.ProjPerFire=50;
  }
}


// infinite flashlight
exec simulated function fl(optional bool bCleanup)
{
  local Effect_TacLightProjector FlashLight;

  if (bCleanup)
  {
    foreach allObjects(class'Effect_TacLightProjector', FlashLight)
      FlashLight.destroy();
    return;
  }

  FlashLight = getPawn().spawn(class'Effect_TacLightProjector', getPawn());
  FlashLight.bHasLight =! FlashLight.bHasLight;
  // old code, uses charge
  // KFWeapon(KFHumanPawn(getController().pawn).weapon).serverSpawnLight();
}


//=============================================================================
//                              AUTOMATIC ACTIONS
//=============================================================================

// Macros which makes life easier
// That's pretty good idea use them with alliases
exec simulated function startTossCash()
{
  getPC(pc);
  stopTossCash();

  if (!isPlayerAlive())
    return;

  a_CashTosser = pc.spawn(class'a_CashTosser');
  a_CashTosser.startTossCash(pc);
}


exec simulated function stopTossCash()
{
  if (a_CashTosser != none)
  {
    a_CashTosser.stopTossCash();
    a_CashTosser.destroy();
    a_CashTosser = none;
  }
}


// tosses all weapons from inventory (except goddamn pipes)
exec simulated function startTossWeapons()
{
  getPC(pc);
  stopAnyWeaponTosserActions();

  if (!isPlayerAlive())
    return;

  a_WeaponTosser = pc.spawn(class'a_WeaponTosser');
  a_WeaponTosser.startTossWeapons(pc);
}


exec simulated function stopTossWeapons()
{
  stopAnyWeaponTosserActions();
}


// buys duals and toss it
exec simulated function startPrinting()
{
  getPC(pc);
  stopAnyWeaponTosserActions();

  if (!isPlayerAlive())
    return;

  if (KFPlayerReplicationInfo(pc.playerReplicationInfo).clientVeteranSkill != class'KFMod.KFVetSharpshooter')
    msg(chr(27)$chr(240)$chr(1)$chr(1)$"WARNING!"@chr(27)$chr(255)$chr(255)$chr(255)$"You are not sharpshooter!");

  a_WeaponTosser = pc.spawn(class'a_WeaponTosser');
  a_WeaponTosser.startPrinting(pc);
}


exec simulated function stopPrinting()
{
  stopAnyWeaponTosserActions();
}


//sells all weapons from inventory
exec simulated function startSellWeapons()
{
  getPC(pc);
  stopAnyWeaponTosserActions();

  if (!isPlayerAlive())
    return;

  a_WeaponTosser = pc.spawn(class'a_WeaponTosser');
  a_WeaponTosser.startSellWeapons(pc);
}


exec simulated function stopSellWeapons()
{
  stopAnyWeaponTosserActions();
}


simulated function stopAnyWeaponTosserActions()
{
  if (a_WeaponTosser != none)
  {
    a_WeaponTosser.stopAnyActions();
    a_WeaponTosser.destroy();
    a_WeaponTosser = none;
  }
}


// Find and kills all actors which do some automatic actions
// (i.e. a_WeaponTosser, a_CashTosser)
// ----------------------------------------------
// Not sure if this function is still needed, since I fixed that glitch
// But better leave it there in case of some shit will happen
exec function clearTrash()
{
  local a_CashTosser ct;
  local a_WeaponTosser wt;

  forEach allObjects(class'a_CashTosser', ct)
  {
    ct.stopTossCash();
    ct.destroy();
  }
  forEach allObjects(class'a_WeaponTosser', wt)
  {
    wt.stopAnyActions();
    wt.destroy();
  }
}


//=============================================================================
//                                HUD FUNCTIONS
//=============================================================================

simulated function PostRender(Canvas C)
{
  // on-off switch, crosshair
  if (bCross)
    class'u_RenderHelper'.static.DrawXhair(C, CrosshairColor, XLength, XWidth);

  // on-off switch, health bars
  if (bHPBar)
    class'u_RenderHelper'.static.DrawHealthBars(getPawn(), C, fHPBar);

  // reveal bitches
  if (bReveal)
    class'u_RenderHelper'.static.RevealStalkers(getPawn());

  DrawHalo();

  // DrawHeadShotSphere(c);
}

// For debugging headshots
// simulated function DrawHeadShotSphere(out Canvas C) // Dave@Psyonix
// {
//   local HUDKillingFloor KFH;
//   local KFHumanPawn p;
//   local KFMonster KFM;
//   local coords CO;
//   local vector HeadLoc;

//   KFH = HUDKillingFloor(C.ViewPort.Actor.myHUD);
//   p = getPawn();

//   if ( p == none || KFH == none)
//     return;

//   //super.DrawHeadShotSphere();

//   foreach p.DynamicActors(class'KFMonster', KFM)
//   {
//     if ( KFM == none ) // && KFM.ServerHeadLocation != KFM.LastServerHeadLocation )
//       continue;
//       //KFM.DrawDebugSphere(KFM.Location + (KFM.OnlineHeadshotOffset >> KFM.Rotation), KFM.HeadRadius * KFM.HeadScale * KFM.OnlineHeadshotScale, 10, 0, 255, 0);
//     KFH.ClearStayingDebugLines();
//     // KFM.LastServerHeadLocation = KFM.ServerHeadLocation;
//     // DrawStayingDebugSphere(KFM.ServerHeadLocation, KFM.HeadRadius * KFM.HeadScale, 10, 128, 255, 255);
//     CO = KFM.GetBoneCoords(KFM.HeadBone);
//     HeadLoc = CO.Origin + (KFM.HeadHeight * KFM.HeadScale * CO.XAxis);
//     KFH.DrawStayingDebugSphere(HeadLoc, KFM.HeadRadius * KFM.HeadScale, 10, 0, 255, 0);
//   }
// }


// set zap effect for bitches
exec simulated function Reveal()
{
  bReveal = !bReveal;
  msg("Reveal status is "$bReveal);
}


// draw zed healthbars
exec simulated function HPBar(optional float range)
{
  if (range > 0)
  {
    fHPBar = range;
    msg("Zed Health Bar detection range changed to "$range);
    return;
  }

  bHPBar = !bHPBar;
  msg("Zed Health Bar is "$bHPBar);
}


// crosshair on-off
exec simulated function Xhair()
{
  bCross = !bCross;
  msg("Crosshair is "$bCross);
}


// huge ass light around player
exec simulated function Halo()
{
  bHalo = !bHalo;
  msg("Halo is "$bHalo);
}


function DrawHalo()
{
  if (bHalo)
  {
    if (HaloLight == none)
      HaloLight = getPawn().spawn(class'Halo', getPawn());
    HaloLight.SetLocation(getPawn().Location);
  }
  else
  {
    if (HaloLight != none)
    {
      HaloLight.Destroy();
      HaloLight = none;
    }
  }
}


//change camera mode
//TODO: Add protection (0 > mode > 9)
exec function cameraMode(int mode)
{
  getPC(pc);
  mode = clamp(mode,0,9);
  pc.rendMap = byte(mode);
}


exec function hideArrow()
{
  local HUDKillingFloor KFH;

  KFH = HUDKillingFloor(getController().myHUD);
  if (KFH == none)
    return;

  KFH.ShopDirPointer.bHidden = !KFH.ShopDirPointer.bHidden;
  msg("Trader arrow status: " $ KFH.ShopDirPointer.bHidden);
}


//=============================================================================
//                           SPEECH and CHAT FUNCTIONS
//=============================================================================

exec simulated function Hlp()
{
  class'u_Helper'.static.TellAbout(getController(),self,"MsgHelp");
}


// 0 delay talking
exec simulated function fastTalk()
{
  local KFConsole console;

  console = KFConsole(viewportOwner.console);

  if (console != none)
  {
    console.typedStr = "Ssay ";
    console.typedStrPos = 5;
    console.typingOpen();
  }
}

// Player.Console.Chat( c$s, 6.0, PRI );
// event TeamMessage( PlayerReplicationInfo PRI, coerce string S, name Type  )
exec simulated function ssay(string msg)
{
  getController().serverSay(msg);
}


exec simulated function warnsc()
{
  ssay(class'u_BindHelper'.static.getString(1));
  ViewportOwner.Actor.Speech('AUTO', 14, "");
}


exec simulated function warnfp()
{
  ssay(class'u_BindHelper'.static.getString(2));
  ViewportOwner.Actor.Speech('AUTO', 12, "");
}


//disables/enables TTS
exec simulated function tts()
{
  getController().bNoTextToSpeechVoiceMessages = !getController().bNoTextToSpeechVoiceMessages;

  if (getController().bNoTextToSpeechVoiceMessages)
  {
    msg("TTS is disabled.");
  }
  else
  {
    msg("TTS is enabled.");
  }
}


exec simulated function spam(string s)
{
  class'ChatAnimator'.static.textspam(getController(),s);
}


exec simulated function fspam(int i)
{
  class'ChatAnimator'.default.spamLoops = i;
}


// // Send a voice message of a certain type to a certain player.
// exec function Speech( name Type, int Index, string Callsign )
// {
//   ServerSpeech(Type,Index,Callsign);
// }

// // if _RO_
// // implemented in ROPlayer
// exec function xSpeech(name Type, int Index, PlayerReplicationInfo SquadLeader) {}
// // end if _RO_

// function ServerSpeech( name Type, int Index, string Callsign )
// {
//   // log("Type:"$Type@"Index:"$Index@"Callsign:"$Callsign);
//   if (PlayerReplicationInfo.VoiceType != none)
//     PlayerReplicationInfo.VoiceType.static.PlayerSpeech( Type, Index, Callsign, self );
// }
exec simulated function insult(int j)
{
  local KFConsole console;
  local int i;

  console = KFConsole(viewportOwner.console);

  if (VoiceClass == none)
  {
    console.SMArraySize = 0;
    console.PreviousStateName = KFSMS_Main;

    VoiceClass = GetKFVoiceClass();
    if (VoiceClass == none)
      return;

    for ( i = 0; i < VoiceClass.Default.NumInsults; i++ )
    {
      if ( VoiceClass.Default.InsultAbbrev[i] != "" )
      {
        console.SMNameArray[console.SMArraySize] = VoiceClass.Default.InsultAbbrev[i];
      }
      else
      {
        console.SMNameArray[console.SMArraySize] = VoiceClass.Default.InsultString[i];
      }
      console.SMIndexArray[console.SMArraySize] = i;
      console.SMArraySize++;
    }
  }

  // KFConsole.uc
  // getController().Speech(SMType, SMIndexArray[i], "");
  ViewportOwner.Actor.Speech('INSULT', console.SMIndexArray[j], "");
 // PlayerReplicationInfo.VoiceType.static.PlayerSpeech( Type, Index, Callsign, self );
  //InsultString
  console.PlayConsoleSound(sound'KF_MenuSnd.msfxMouseClick');
}


simulated function class<KFVoicePack> GetKFVoiceClass()
{
  local KFPlayerReplicationInfo rop;
  // NewVoiceType = class<VoicePack>(DynamicLoadObject(S, class'Class', true));

  if ( ViewportOwner == none || ViewportOwner.Actor == none || ViewportOwner.Actor.PlayerReplicationInfo == none )
  {
    return none;
  }

  rop = KFPlayerReplicationInfo(ViewportOwner.Actor.PlayerReplicationInfo);

  return class<KFVoicePack>(rop.VoiceType);
}


// show pat health
exec simulated function PatHP(optional bool bPublic)
{
  local ZombieBoss kfm;
  local string message;
  local int i;

  forEach getController().allActors(class'ZombieBoss', kfm)
  {
    if (kfm == none || kfm.health <= 0)
      continue;

    i++;

    message = class'u_Helper'.static.ParseTags("^w" $ i $ ". Pat's health is ^b"$kfm.health$" ^w/ ^b"$kfm.HealthMax $"^w. Syringes used - ^b" $ kfm.SyringeCount);
    if (!bPublic)
      msg(message);
    else
      ssay(message);
  }
}


// shows spawbed zeds count
exec simulated function mz(optional bool bPublic)
{
  local KFMonster kfm;
  local string message;
  local int i;

  forEach getController().allActors(class'KFMonster', kfm)
  {
    if (kfm == none || kfm.health <= 0)
      continue;

    i++;
  }

  message = class'u_Helper'.static.ParseTags("^w Spawned zeds count - ^b" $ i $ "^w.");
  if (!bPublic)
    msg(message);
  else
    ssay(message);
}


//=============================================================================
//                           RANDOM EXEC FUNCTIONS
//=============================================================================
// Just some usefull executable functons
exec simulated function dropweapon(string newCharacter)
{
  local KFHumanPawn me;
  local Vector TossVel;

  me = getPawn();
  getPC(pc);
  if (pc == none || me == none || me.Weapon == none)
    return;
  me.ChangedWeapon();
  pc.ThrowWeapon();

  TossVel = Vector(pc.GetViewRotation());
  TossVel = TossVel * ((me.Velocity dot TossVel) + 150) + Vect(0,0,100);
  me.TossWeapon(TossVel);
  pc.ClientSwitchToBestWeapon();
}

// Changes pawn skin
exec simulated function cc(string newCharacter)
{
  getController().ConsoleCommand("ChangeCharacter " $ newCharacter);
}

// Does the team kill.
// Shot -> waiting for 'timerTime' -> spectate -> back in game
exec simulated function teamKill(float timerTime)
{
  local a_SpectateManager sm;

  sm = getController().spawn(class'a_SpectateManager');
  sm.friendlyShoot(getController(), timerTime);
}

// log in as administrator/log off
// uses admin accounts from config
exec simulated function adlog()
{
  class'u_AdminInfo'.static.login(getController());
}

//returns player to lobby menu if match haven't started yet
exec simulated function lobby()
{
  getController().showLobbyMenu();
}

//=============================================================================
//                              EXPEREMENTAL
//=============================================================================

exec simulated function vt(string cmd)
{
  local xVotingHandler V;
  local int i;

  getpc(pc);

  V = xVotingHandler(pc.Level.Game.VotingHandler);
  if (V == none)
    return;

  if (Cmd ~= "Cancel")
  {
    V.bMidGameVote = False;
    V.settimer(0,False);
    for( i=0; i<V.MVRI.Length; i++ )
    {
      if ( V.MVRI[i]!=none && V.MVRI[i].MapVote>-1 && V.MVRI[i].GameVote>-1 )
      {
        V.UpdateVoteCount(V.MVRI[i].MapVote,V.MVRI[i].GameVote,-V.MVRI[i].VoteCount);
        V.MVRI[i].MapVote = -1;
        V.MVRI[i].GameVote = -1;
        V.MVRI[i].VoteCount = 0;
      }
    }
    V.TallyVotes(false);
    //Level.Game.Broadcast(Outer,"Mapvoting has been canceled");
    // AMessage("Mapvoting canceled");
  }
  else if (Cmd ~= "Begin")
  {
    // AMessage("Started mapvoting");
    //Level.Game.Broadcast(V,V.lmsgMidGameVote);
    V.bMidGameVote = true;
    // Start voting count-down timer
    V.TimeLeft = V.VoteTimeLimit;
    V.ScoreBoardTime = 1;
    V.settimer(1,true);
  }
}


exec function pickActor()
{
  checkVisibilityHandler();
  a_visibilityHandler.pickActor();
}


exec function doTheMagic()
{
  checkVisibilityHandler();
  a_visibilityHandler.doTheMagic();
}


exec simulated function print()
{
  bRequiresTick = !bRequiresTick;
  bBuyMode = bRequiresTick;
  msg("Tick is " $bRequiresTick);
}


function Tick(float DeltaTime)
{
  local int i;

  if (bBuyMode)
  {
    class'u_WeaponHelper'.static.print(getPawn());
    i++;
  }

  if (!bInitialized && class'Settings'.default.bRandomName && KFPlayerReplicationInfo(ViewportOwner.Actor.PlayerReplicationInfo) != none)
  {
    SN(class'u_BindHelper'.static.getString(0));
    bInitialized = true;
    bRequiresTick = false;
    i++;
  }

  // auto shutdown, we don't want this tick to run forever
  // 30 seconds as a test!
  if (i >= 3600)
  {
    msg("Tick is disabled! It was running for too long!");
    bRequiresTick = !bRequiresTick;
  }

  // remove negative visible effects from pawn
  // while (me != none )
  // {
  //   me.bBurnified = false;
  //   me.BileCount = 0;
  //   me.BurnDown = 0;
  //   me.RemoveFlamingEffects();
  //   me.StopBurnFX();
  // }

  // if (me.secondaryItem != none)
  // {
  //    tempSecondaryItem = me.secondaryItem;
  //    getController().ClientMessage(string(me.secondaryItem));
  //    getController().ClientMessage(string(me.secondaryItem.role));
  //    getController().ClientMessage(string(me.secondaryItem.remoteRole));
  //    //me.secondaryItem.spawn(class'ZombieClot');
  // }
  // //me.secondaryItem = me.secondaryItem.spawn(class'M79GrenadeLauncher');
  // me.secondaryItem.spawn(class'frag');

  // local KFPlayerController kfpc;

  // kfpc = getController();

  // if (kfpc == none)
  //   return;

  // // Unshakable by nullifying vectors and rotators
  // kfpc.shakeOffsetRate = vect(0,0,0);
  // kfpc.shakeOffset = vect(0,0,0); //current magnitude to offset camera from shake
  // kfpc.shakeOffsetTime = vect(0,0,0);
  // kfpc.shakeOffsetMax = vect(0,0,0);
  // kfpc.shakeRotRate = vect(0,0,0);
  // kfpc.shakeRotMax = vect(0,0,0);
  // kfpc.shakeRot.pitch = 0;
  // kfpc.shakeRot.yaw = 0;
  // kfpc.shakeRot.roll = 0;
  // kfpc.shakeRotTime = vect(0,0,0);
}


// Debug PostFX effects
exec function DebugBWEffect(float NewAmount)
{
  if ( NewAmount > 0 )
  {
    postfxon(2);
    postfxbw(NewAmount);
  }
  else
  {
    postfxoff(2);
  }
}

simulated function postfxbw(float f, optional bool bDoNotTurnOffFadeFromBlackEffect)  //0... 1
{
  if ( !getController().PostFX_IsReady() )
    return;

  //if (!bDoNotTurnOffFadeFromBlackEffect)
  //  bDoFadeFromBlackEffect = false;

  getController().PostFX_SetParameter(2, 0, f);
}

simulated function postfxon(int i)
{
  if ( getController().PostFX_IsReady() )
    getController().PostFX_SetActive(i, true);
}

simulated function postfxoff(int i)
{
  if ( getController().PostFX_IsReady() )
    getController().PostFX_SetActive(i, false);
}

exec simulated function SS(float sens)
{
  getController().SetSensitivity(sens);
  msg("Mouse sensitivity set to" @ sens);
}

// Change Alias
exec simulated function SA(string Alias)
{
  bCP = true;
  if (Alias != "")
  {
    Switch(Alias)
    {
      Case "0":
        NewChar("Mr_Foster");
        NewName("Joabyy");
        break;
      Case "1":
        NewChar("Mr_Foster");
        NewName("Joabyy");
        break;
      Case "1a":
        NewChar("Steampunk_Mrs_Foster");
        NewName("Joabyy","(Steampunk Mrs Foster)");
        break;
      Case "1b":
        NewChar("Steampunk_Mrs_Foster");
        NewName("Aya");
        break;
      Case "1c":
        NewChar("Steampunk_Mrs_Foster");
        NewName("Aya Kawasaki");
        break;
      Case "1d":
        NewChar("Steampunk_Mrs_Foster");
        NewName("Yui Hatano");
        break;
      Case "1e":
        NewChar("Steampunk_Mrs_Foster");
        NewName("Yua Sakuya");
        break;
      Case "2":
        NewChar("Steampunk_Mrs_Foster");
        NewName("fuzzy");
        break;
      Case "3":
        NewChar("Pyro_Blue");
        NewName("devante");
        break;
      Case "4":
        NewChar("Ash_harding");
        NewName("Galaxies.");
       break;
      Case "4a":
        NewChar("Ash_harding");
        NewName("nessiebugs");
        break;
      Case "5":
        NewChar("Security_Officer_Thorne");
        NewName("dev1l");
        break;
      Case "6":
        NewChar("Shadow_Ferret");
        NewName("LuKaS");
        break;
      Case "7":
        NewChar("Reaper");
        NewName("(MI) Markv39");
        break;
      Case "8":
        NewChar("Commando_Chicken");
        NewName("iNK");
        break;
      Case "9":
        NewChar("Mr_Foster");
        NewName("Static.");
        break;
    }
  }
}

//Change Character
exec simulated function SC(string Char)
{
  bCP = false;
  if (Char != "")
  {
    Switch(Char)
    {
      Case "1": NewChar("Mr_Foster");
        break;
      Case "2": NewChar("Steampunk_Mrs_Foster");
        break;
      Case "3": NewChar("Dr_Gary_Glover");
        break;
      Case "4": NewChar("Ash_harding");
        break;
      Case "5": NewChar("Security_Officer_Thorne");
        break;
      Case "6": NewChar("Mike_Noble");
        break;
      Case "7": NewChar("Shadow_Ferret");
        break;
      Case "8": NewChar("Pyro_Blue");
        break;
      Case "9": NewChar("Pyro_Red");
        break;
      Case Char: NewChar(Char);
        break;
    }
  }
}

exec simulated function NewChar(string Char)
{
  getPC(pc);

  pc.setPawnClass(string(pc.pawnClass), Char);
  pc.updateURL("Character", Char, true);
  pc.saveConfig();
  if (bcp)
    return;
  msg("Character changed to" @ Char);
}

exec simulated function SN(coerce optional string Name)
{
  // Player.GUIController.SteamGetUserName()
  // replaces spaces with no-break spaces to avoid changing it to underscores
  if (name ~= "null")
    Name = chr(10);
  else
    replaceText(Name, chr(32), chr(160));
  getController().changeName(Name);
  msg("Name changed to" @ Name);
}

function NewName(optional string Name, optional string Char)
{
  replaceText(Name, chr(32), chr(160));
  getController().changeName(Name);
  if (bCP)
    msg("Alias changed to" @ Name @ Char);
  else
    msg("Name changed to" @ Name);
}

exec simulated function rc()
{
  getController().ConsoleCommand("Reconnect");
  msg("Reconnecting to server.");
}

exec simulated function dc()
{
  getController().ConsoleCommand("Disconnect");
  msg("Disconnecting!");
}

exec function sSpec()
{
  getController().ServerSpectate();
}

exec simulated function Spec()
{
  getController().BecomeSpectator();
}

exec simulated function Join()
{
  getController().BecomeActivePlayer();
}

exec simulated function vnade(optional bool b)
{
  if (!b)
    getController().ConsoleCommand("set input g nade");
  else
    getController().ConsoleCommand("set input g thrownade");
}

exec simulated function Q1()
{
  getController().ConsoleCommand("set input Q switchtolastweapon | quickheal");
  msg("Quick heal bound to Q");
}

exec simulated function Q2()
{
  getController().ConsoleCommand("set input Q ReallyQuickHeal");
  msg("ReallyQuickHeal bound to Q");
}

exec simulated function G1()
{
  getController().ConsoleCommand("Set input G poof");
  msg("Poof bound to G");
}

exec simulated function G2()
{
  getController().ConsoleCommand("Set input G Admin summon kfmod.pipebombprojectile");
  msg("Pipe spam bound to G");
}

exec simulated function G3()
{
  getController().ConsoleCommand("set input G StartTossCash | OnRelease StopTossCash");
  msg("Dosh spam bound to G");
}

exec simulated function G4()
{
  getController().ConsoleCommand("set input G admin summon KFMod.KFHorzineSoldier");
  msg("Bot spam bound to G");
}

exec simulated function G5()
{
  getController().ConsoleCommand("set input G admin summon KFMod.M99Bullet");
  msg("M99 Bullet spam bound to G");
}

exec simulated function G6()
{
  getController().ConsoleCommand("set input G admin summon KFMod.ZEDMKIISecondaryProjectile");
  msg("Zed gun II Alt fire bound to G");
}

//restart wave 10
exec simulated function RES()
{
  getController().ConsoleCommand("AdLog");
  getController().ConsoleCommand("admin pw");
  getController().ConsoleCommand("admin wave 10");
  getController().ConsoleCommand("admin restore");
  getController().ConsoleCommand("admin skip");
}

//lock server
exec simulated function LS()
{
  getController().ConsoleCommand("mutate slot 0");
  getController().ConsoleCommand("mutate spec 0");
}

exec simulated function LS1()
{
  getController().ConsoleCommand("mutate slot 0");
  getController().ConsoleCommand("mutate spec 0");
  NewName("Aya");
}

//unlock server
exec simulated function US()
{
  getController().ConsoleCommand("mutate slot 6");
  getController().ConsoleCommand("mutate spec 32");
}

exec simulated function f1()
{
  getController().ConsoleCommand("mutate faked 6");
  getController().ConsoleCommand("mutate hp 6");
}

exec simulated function f2()
{
  getController().ConsoleCommand("mutate faked 4");
  getController().ConsoleCommand("mutate hp 6");
}

exec simulated function f4()
{
  local bool B;

  getPC(pc);
  B = !pc.bBehindView;

  pc.ClientSetBehindView(B);
  pc.bBehindView = B;
  // PlayerController(c).ClientSetBehindView(false);
  // PlayerController(c).bBehindView = false;
  if (!pc.bBehindView)
  {
    pc.SetViewTarget(pc.pawn);
    pc.ClientSetViewTarget(pc.pawn);
    // KFHumanPawn(KFPlayerController(viewportOwner.actor).pawn);
    // PlayerController(c).SetViewTarget(c.Pawn);
    // PlayerController(c).ClientSetViewTarget(c.Pawn);
  }

  // PlayerController(c).SetViewTarget(ViewingBoss);
  // PlayerController(c).ClientSetViewTarget(ViewingBoss);
  // PlayerController(c).bBehindView = true;
  // PlayerController(c).ClientSetBehindView(true);
  // PlayerController(c).ClientSetMusic(BossBattleSong,MTRAN_FastFade);
}


exec simulated function camdist(float dist)
{
  getPC(pc);
  if (!isPlayerAlive())
    return;

  pc.default.CameraDist = dist;
}


//=============================================================================
//                                  PERKS
//=============================================================================
// Following functions allow player to change his perk
// Infinite number of times (during trader) and pick any level


exec simulated function bSharp(optional string s)
{
  class'u_PerkList'.static.PerkSwitch(getController(), 0, s);
}


exec simulated function bMed(optional string s)
{
  class'u_PerkList'.static.PerkSwitch(getController(), 1, s);
}


exec simulated function bZerk(optional string s)
{
  class'u_PerkList'.static.PerkSwitch(getController(), 2, s);
}


exec simulated function bMando(optional string s)
{
  class'u_PerkList'.static.PerkSwitch(getController(), 3, s);
}


exec simulated function bDemo(optional string s)
{
  class'u_PerkList'.static.PerkSwitch(getController(), 4, s);
}


exec simulated function bPyro(optional string s)
{
  class'u_PerkList'.static.PerkSwitch(getController(), 5, s);
}


exec simulated function bSup(optional string s)
{
  class'u_PerkList'.static.PerkSwitch(getController(), 6, s);
}


exec simulated function bNone()
{
  class'u_PerkList'.static.PerkSwitch(getController(), 7);
}


// This function is needed on custom gametypes like ScrN
exec simulated function vet(string vetName)
{
  local class<KFVeterancyTypes> changeToVeterancy;

  changeToVeterancy = class<KFVeterancyTypes>(dynamicLoadObject(vetName, class'Class', true));
  getController().selectVeterancy(changeToVeterancy, true);
}


// disables perk progression
exec simulated function greyList()
{
  getController().bwEffect(0);
}


//=============================================================================
//                                  DEBUG
//=============================================================================

//Shoots projectile which returns the name of object projectile bumps into
exec simulated function getActorName()
{
  getPC(pc);
  if (pc.pawn != none)
    pc.spawn(class'GetNameProj', pc, , pc.pawn.location + pc.pawn.eyeHeight * vect(0, 0, 1), pc.rotation);
  else
    pc.spawn(class'GetNameProj', pc, , pc.location, pc.rotation);
}


// current ctrl and pri info
exec simulated function getC()
{
  local KFPlayerController kfpc;
  local KFPlayerReplicationInfo kfri;
  local string names;
  local int i;

  forEach allObjects(class'KFPlayerReplicationInfo', kfri)
  {
    if (kfri == none || kfri.PlayerID == 0)
      continue;
    names @= kfri.PlayerName;
    i++;
  }
  msg("KFPlayerReplicationInfo count is " $ i $ ", names are" $ names);

  i = 0;
  foreach allObjects(class'KFPlayerController', kfpc)
  {
    if (kfpc == none || kfpc.PlayerReplicationInfo.PlayerID == 0)
      continue;
    i++;
  }
  msg("KFPlayerController count is " $ i);
}


// gametype name
exec simulated function getGt()
{
  local GameReplicationInfo gri;

  foreach allObjects(class'GameReplicationInfo', gri)
  {
    if (gri == none)
      continue;
    msg("GameType is: " $ gri.gameClass);
  }
}


// print map name
exec simulated function getMap()
{
  local string mapName;
  // local int i;

  mapName = class'KFGameType'.static.getCurrentMapName(getController().level);
  msg(mapName);
  // getController().clientMessage(""$a_visibilityHandler.getCurrentMapName());
}


// print IP info
exec simulated function getIP()
{
  getPC(pc);
  msg(pc.getServerNetworkAddress());
}


exec simulated function getLoc()
{
  local vector loc;

  if (getPawn() != none)
    loc = getPawn().location;
  else if (getController() != none)
    loc = getController().location;

  msg("Location is: " $ loc);
}


// print character list
exec simulated function getChar()
{
  class'u_Helper'.static.TellAbout(getController(),self,"Chars");
}


// crash your game, might be helpful xD
exec simulated function crashS()
{
  KFPlayerReplicationInfo(getController().PlayerReplicationInfo).static.crash();
}


//=============================================================================
//                              EXPEREMENTAL
//=============================================================================

exec function sp(optional bool b)
{
  Msg("Forcing path visibility to: " $ b);

  checkVisibilityHandler();
  a_visibilityHandler.showPathNodes(b);
  class'u_RenderHelper'.static.ShowPaths(getController(), b);
}


exec simulated function showkills()
{
  local HUDKillingFloor KFH;

  KFH = HUDKillingFloor(getController().myHUD);
  KFH.SetPropertyText("bTallySpecimenKills", "true");
}


exec simulated function setXY(int x, int y)
{
  Msg("X is " $ x $ " and Y is " $ y);
}


//lock server
exec simulated function test()
{
  getController().ConsoleCommand("adlog");
  getController().ConsoleCommand("admin ready");
  getController().ConsoleCommand("admin god");
  getController().ConsoleCommand("admin dosh all 500000");
  getController().ConsoleCommand("admin trader 6000 1");
  getController().ConsoleCommand("admin skip");
  getController().ConsoleCommand("admin wave 2");
}


//=============================================================================
defaultproperties
{
  bVisible=true
}