local Cron = require('Cron')

local socket = nil

local invul = false
local ohko = false
local oldhealth = 0

local infstam = false
local nostam = false

local oldspeed = 0
local oldjump = 0

local oldfov = 0
local hop = false

local teletime = 0

local lasttime = 0
local frozen = false

function split (inputstr, sep)
  if sep == nil then
          sep = "%s"
  end
  local t={}
  for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
          table.insert(t, str)
  end
  return t
end

CC = {}

function isReady()
    local player = Game.GetPlayer()
    if not player then return false end
    if Game.GetTimeSystem():IsPausedState() then return false end
    if player:IsDead() then return false end
    if teletime > 0 then return false end
    if frozen then return false end

    return true

end

local viewer = ""

local function OnCommand(command)

    print("raw message: " .. command)

    local items = split(command, " ")

    local effid = items[1]

    items = split(items[2], ":")

    viewer = "Crowd Control"

    if #items > 1 then
        if items[2] ~= "" then
            viewer = items[2]
        end
    end

    local arg = ""

    local parts = split(items[1], "_")

    if #parts > 1 then
        arg = parts[2]
    end

    local ret = false

    print(effid .. " Command: " .. parts[1] .. " arg: " .. arg .. " viewer: " .. viewer)

    if isReady() then
        if parts[1] == "money" then ret = cc_money(arg) end
        if parts[1] == "tmoney" then ret = cc_tmoney(arg) end
        if parts[1] == "damage" then ret = cc_damage(arg) end
        if parts[1] == "heal" then ret = cc_heal(arg) end
        if parts[1] == "kill" then ret = cc_kill(arg) end
        if parts[1] == "stamup" then ret = cc_stamup(arg) end
        if parts[1] == "stamdown" then ret = cc_stamdown(arg) end

        if parts[1] == "invul" then ret = cc_invul(arg) end
        if parts[1] == "ohko" then ret = cc_ohko(arg) end
        if parts[1] == "infstam" then ret = cc_infstam(arg) end
        if parts[1] == "nostam" then ret = cc_nostam(arg) end

        if parts[1] == "slow" then ret = cc_slow(arg) end
        if parts[1] == "uslow" then ret = cc_uslow(arg) end
        if parts[1] == "fast" then ret = cc_fast(arg) end
        if parts[1] == "hyper" then ret = cc_hyper(arg) end
        if parts[1] == "freeze" then ret = cc_freeze(arg) end

        if parts[1] == "nojump" then ret = cc_nojump(arg) end
        if parts[1] == "lowjump" then ret = cc_lowjump(arg) end
        if parts[1] == "highjump" then ret = cc_highjump(arg) end
        if parts[1] == "moonjump" then ret = cc_moonjump(arg) end
        if parts[1] == "launch" then ret = cc_launch(arg) end
        if parts[1] == "bunnyhop" then ret = cc_bunnyhop(arg) end

        if parts[1] == "wide" then ret = cc_wide(arg) end
        if parts[1] == "narrow" then ret = cc_narrow(arg) end

        if parts[1] == "level" then ret = cc_level(arg) end
        if parts[1] == "cred" then ret = cc_cred(arg) end
        if parts[1] == "attup" then ret = cc_attup(arg) end
        if parts[1] == "attdown" then ret = cc_attdown(arg) end
        if parts[1] == "perkup" then ret = cc_perkup(arg) end
        if parts[1] == "perkdown" then ret = cc_perkdown(arg) end

        if parts[1] == "attrup" then ret = cc_attrup(arg) end
        if parts[1] == "attrdown" then ret = cc_attrdown(arg) end    
        if parts[1] == "skillup" then ret = cc_skillup(arg) end
        if parts[1] == "skilldown" then ret = cc_skilldown(arg) end    

        if parts[1] == "travel" then ret = cc_travel(arg) end
        if parts[1] == "telehome" then ret = cc_telehome(arg) end
        if parts[1] == "teleclub" then ret = cc_teleclub(arg) end
        if parts[1] == "teleshop" then ret = cc_teleshop(arg) end

        if parts[1] == "weap" then ret = cc_weap(arg) end
        if parts[1] == "item" then ret = cc_item(arg) end
        if parts[1] == "take" then ret = cc_take(arg) end

        if parts[1] == "explode" then ret = cc_explode(arg) end
        if parts[1] == "spawn" then ret = cc_spawn(arg) end
        if parts[1] == "spawncar" then ret = cc_spawncar(arg) end
        if parts[1] == "status" then ret = cc_status(arg) end
        if parts[1] == "spam" then ret = cc_spam(arg) end
    end
    
    if ret then
        socket:SendCommand(effid .. " success")
    else
        socket:SendCommand(effid .. " retry")
    end
end

function cc_status(val)
    local status = nil
    
    if val == "blind" then status = "BaseStatusEffect.Blind" end
    if val == "burning" then status = "BaseStatusEffect.Burning" end
    if val == "bleeding" then status = "BaseStatusEffect.Bleeding" end
    if val == "drunk" then status = "BaseStatusEffect.Drunk" end
    if val == "electrocuted" then status = "BaseStatusEffect.Electrocuted" end
    if val == "emp" then status = "BaseStatusEffect.EMP" end
    if val == "grappled" then status = "BaseStatusEffect.Grappled" end
    if val == "knockdown" then status = "BaseStatusEffect.SecondaryKnockdown" end
    if val == "stun" then status = "BaseStatusEffect.Stun" end

    print(status)

    if status == nil then return false end

    if Game.GetStatusEffectSystem():HasStatusEffect(Game.GetPlayer():GetEntityID(), status) then
        return false
    end

    Game.GetStatusEffectSystem():ApplyStatusEffect(Game.GetPlayer():GetEntityID(), status)
    return true
end

function cc_travel(val)
    local UIS = Game.GetUISystem(); UIS:RequestFastTravelMenu()

    show_message(viewer .. " opened fast travel")
    
    return true
end

function cc_level(val)
    local ProfType = gamedataProficiencyType.Level
    local devData = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())
    local currentLevel = devData:GetProficiencyLevel(ProfType)

    if currentLevel >= 60 then
        return false
    end

    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())
    local ExpAmount = DS:GetRemainingExpForLevelUp(ProfType)
    DS:AddExperience(ExpAmount, ProfType, telemetryLevelGainReason.Gameplay)

    show_message(viewer .. " leveled you up")

    return true
end

function cc_cred(val)
    local ProfType = gamedataProficiencyType.StreetCred
    local devData = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())
    local currentLevel = devData:GetProficiencyLevel(ProfType)

    if currentLevel >= 50 then
        return false
    end


    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())
    local ExpAmount = DS:GetRemainingExpForLevelUp(ProfType)
    DS:AddExperience(ExpAmount, ProfType, telemetryLevelGainReason.Gameplay)

    show_message(viewer .. " raised your street cred")
    return true
end

function cc_attup(val)
    local AttPoints = 1;
    local PointType = gamedataDevelopmentPointType.Attribute;
    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())

    local cur = DS:GetDevPoints(PointType)
    if cur > 20 then return false end

    DS:AddDevelopmentPoints(AttPoints, PointType)

    show_message(viewer .. " gave you an attribute point")
    return true
end

function cc_attdown(val)
    local AttPoints = -1;
    local PointType = gamedataDevelopmentPointType.Attribute;
    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())

    local cur = DS:GetDevPoints(PointType)
    if cur < 1 then return false end

    DS:AddDevelopmentPoints(AttPoints, PointType)
    show_message(viewer .. " took an attribute point")
    return true
end

function cc_attrup(val)
    local AttrType = nil
    
    if val == "body" then AttrType = gamedataStatType.Strength end
    if val == "reflexes" then AttrType = gamedataStatType.Reflexes end
    if val == "tech" then AttrType = gamedataStatType.TechnicalAbility end
    if val == "int" then AttrType = gamedataStatType.Intelligence end
    if val == "cool" then AttrType = gamedataStatType.Cool end

    if AttrType == nil then return false end

    local player = Game.GetPlayer()
    local statsSystem = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    local LvL = statsSystem:GetStatValue(entityID, AttrType)

    if LvL >= 20 then return false end

    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())

    DS:SetAttribute(AttrType, LvL + 1)
    show_message(viewer .. " raised your ".. val)
    return true
end

function cc_attrdown(val)
    local AttrType = nil
    
    if val == "body" then AttrType = gamedataStatType.Strength end
    if val == "reflexes" then AttrType = gamedataStatType.Reflexes end
    if val == "tech" then AttrType = gamedataStatType.TechnicalAbility end
    if val == "int" then AttrType = gamedataStatType.Intelligence end
    if val == "cool" then AttrType = gamedataStatType.Cool end

    if AttrType == nil then return false end

    local player = Game.GetPlayer()
    local statsSystem = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    local LvL = statsSystem:GetStatValue(entityID, AttrType)
    if LvL <= 1 then return false end

    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())

    DS:SetAttribute(AttrType, LvL - 1)
    show_message(viewer .. " lowered your " .. val)
    return true
end

function cc_skillup(val)
    local AttrType = nil
    
    if val == "headhunter" then AttrType = gamedataStatType.CoolSkill end
    if val == "netrunner" then AttrType = gamedataStatType.IntelligenceSkill end
    if val == "shinobi" then AttrType = gamedataStatType.ReflexesSkill end
    if val == "solo" then AttrType = gamedataStatType.StrengthSkill end
    if val == "engineer" then AttrType = gamedataStatType.TechnicalAbilitySkill end

    if AttrType == nil then return false end

    local ProfType = nil
    
    if val == "headhunter" then ProfType = gamedataProficiencyType.CoolSkill end
    if val == "netrunner" then ProfType = gamedataProficiencyType.IntelligenceSkill end
    if val == "shinobi" then ProfType = gamedataProficiencyType.ReflexesSkill end
    if val == "solo" then ProfType = gamedataProficiencyType.StrengthSkill end
    if val == "engineer" then ProfType = gamedataProficiencyType.TechnicalAbilitySkill end

    local player = Game.GetPlayer()
    local ss = Game.GetStatsSystem()
    local id = player:GetEntityID()

    local LvL = ss:GetStatValue(id, AttrType)
    if LvL >= 60 then return false end

    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer());

    DS:SetLevel(ProfType, LvL+1, telemetryLevelGainReason.Gameplay)
    show_message(viewer .. " raised your " .. val)
    return true
end

function cc_skilldown(val)
    local AttrType = nil
    
    if val == "headhunter" then AttrType = gamedataStatType.CoolSkill end
    if val == "netrunner" then AttrType = gamedataStatType.IntelligenceSkill end
    if val == "shinobi" then AttrType = gamedataStatType.ReflexesSkill end
    if val == "solo" then AttrType = gamedataStatType.StrengthSkill end
    if val == "engineer" then AttrType = gamedataStatType.TechnicalAbilitySkill end

    if AttrType == nil then return false end

    local ProfType = nil
    
    if val == "headhunter" then ProfType = gamedataProficiencyType.CoolSkill end
    if val == "netrunner" then ProfType = gamedataProficiencyType.IntelligenceSkill end
    if val == "shinobi" then ProfType = gamedataProficiencyType.ReflexesSkill end
    if val == "solo" then ProfType = gamedataProficiencyType.StrengthSkill end
    if val == "engineer" then ProfType = gamedataProficiencyType.TechnicalAbilitySkill end

    local player = Game.GetPlayer()
    local ss = Game.GetStatsSystem()
    local id = player:GetEntityID()

    local LvL = ss:GetStatValue(id, AttrType)
    if LvL <= 1 then return false end

    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer());

    DS:SetLevel(ProfType, LvL-1, telemetryLevelGainReason.Gameplay)
    show_message(viewer .. " lowered your " .. val)
    return true
end

function forceUnequipSlot(equipArea, slot)
    local P = Game.GetPlayer()
    local ES = Game.GetScriptableSystemsContainer():Get('EquipmentSystem')
    local PD = ES:GetPlayerData(P)
    local areaIndex = PD:GetEquipAreaIndex(gamedataEquipmentArea[equipArea])
    local forceRemove = true
    PD:UnequipItem(areaIndex, slot, forceRemove)
end 

function cc_weap(val)
    local item = nil

    if val == "pistol" then
        item = "Items.Preset_Unity_Default"
    end
    if val == "revolver" then
        item = "Items.Preset_Nova_Default"
    end
    if val == "rifle" then
        item = "Items.Preset_Copperhead_Default"
    end
    if val == "smg" then
        item = "Items.Preset_Pulsar_Default"
    end
    if val == "shotgun" then
        item = "Items.Preset_Carnage_Default"
    end
    if val == "sniper" then
        item = "Items.Preset_Grad_Default"
    end

    if val == "katana" then
        item = "Items.Preset_Katana_Default"
    end
    if val == "bat" then
        item = "Items.Preset_Bat_Default"
    end
    if val == "techrifle" then
        item = "Items.Preset_Achilles_Default"
    end
    if val == "smartassault" then
        item = "Items.Preset_Pulsar_Default"
    end
    if val == "precision" then
        item = "Items.Preset_Sor22_Default"
    end
    if val == "machine" then
        item = "Items.Preset_Defender_Default"
    end
    if val == "skippy" then
        item = "Items.Preset_Yukimura_Skippy"
    end
    if val == "malorian" then
        item = "Items.Preset_Silverhand_Pistol"
    end
    if val == "erebus" then
        item = "Items.Preset_Canto_Erebus"
    end
    if val == "comrade" then
        item = "Items.Preset_Burya_Comrade"
    end
    if val == "baxing" then
        item = "Items.Preset_Zhuo_Eight_Star"
    end
    if val == "byakko" then
        item = "Items.Preset_Katana_Cocktail"
    end
    if val == "phallustiff" then
        item = "Items.Preset_Baton_Tinker_Bell"
    end
    if val == "guts" then
        item = "Items.Preset_Carnage_Edgerunners"
    end
    if val == "fenrir" then
        item = "Items.VHard_50_IntTech_Weapon5"
    end
    if val == "satori" then
        item = "Items.Preset_Katana_Saburo"
    end
    if val == "overwatch" then
        item = "Items.VHard_50_CoolRef_Weapon4"
    end
    if val == "hercules" then
        item = "Items.Preset_Prototype_Hercules"
    end

    if item == nil then return false end

    local player = Game.GetPlayer()
    local transactionSystem = Game.GetTransactionSystem()
    local itemID = ItemID.FromTDBID(item)



    local eqSystem = Game.GetScriptableSystemsContainer():Get(CName.new('EquipmentSystem'))
    local eqData = eqSystem:GetPlayerData(player)

    
    forceUnequipSlot('Weapon', 0)

    RPGManager.ForceEquipItemOnPlayer(player, item, true)
    show_message(viewer .. " gave you a " .. val)
    return true
end

function cc_item(val)
    show_message(viewer .. " gave you an item")

    if val == "common" then
        AddToInventory("Items.CommonMaterial1", 5)
        return true
    end
    if val == "uncommon" then
        AddToInventory("Items.UncommonMaterial1", 5)
        return true
    end
    if val == "rare" then
        AddToInventory("Items.RareMaterial1", 5)
        return true
    end
    if val == "epic" then
        AddToInventory("Items.EpicMaterial1", 5)
        return true
    end
    if val == "legendary" then
        AddToInventory("Items.LegendaryMaterial1", 5)
        return true
    end

    if val == "maxdoc1" then
        AddToInventory("Items.FirstAidWhiffV0", 1)
        return true
    end
    if val == "maxdoc3" then
        AddToInventory("Items.FirstAidWhiffV1", 1)
        return true
    end
    if val == "maxdoc5" then
        AddToInventory("Items.FirstAidWhiffV2", 1)
        return true
    end

    if val == "bounce1" then
        AddToInventory("Items.BonesMcCoy70V0", 1)
        return true
    end
    if val == "bounce3" then
        AddToInventory("Items.BonesMcCoy70V1", 1)
        return true
    end
    if val == "bounce5" then
        AddToInventory("Items.BonesMcCoy70V2", 1)
        return true
    end


    if val == "handgunammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.HandgunAmmo"))
        if qty >= 999 then
            return false
        end

        AddToInventory("Ammo.HandgunAmmo", 25)

        return true
    end
    if val == "shotgunammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.ShotgunAmmo"))
        if qty >= 199 then
            return false
        end

        AddToInventory("Ammo.ShotgunAmmo", 10)
        return true
    end
    if val == "rifleammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.RifleAmmo"))
        if qty >= 999 then
            return false
        end

        AddToInventory("Ammo.RifleAmmo", 25)
        return true
    end    
    if val == "sniperammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.SniperRifleAmmo"))
        if qty >= 99 then
            return false
        end

        AddToInventory("Ammo.SniperRifleAmmo", 5)
        return true
    end    


    return false
end



function cc_take(val)
    show_message(viewer .. " took your ammo")

    if val == "handgunammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.HandgunAmmo"))
        if qty <= 0 then
            return false
        end

        Game.GetTransactionSystem():RemoveItem(Game.GetPlayer(), ItemID.FromTDBID("Ammo.HandgunAmmo"), 25)
        AddToInventory("Ammo.HandgunAmmo", 0)

        print("added handgun ammo")
        return true
    end
    if val == "shotgunammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.ShotgunAmmo"))
        if qty <= 0 then
            return false
        end

        Game.GetTransactionSystem():RemoveItem(Game.GetPlayer(), ItemID.FromTDBID("Ammo.ShotgunAmmo"), 25)
        AddToInventory("Ammo.ShotgunAmmo", 0)
        return true
    end
    if val == "rifleammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.RifleAmmo"))
        if qty <= 0 then
            return false
        end

        Game.GetTransactionSystem():RemoveItem(Game.GetPlayer(), ItemID.FromTDBID("Ammo.RifleAmmo"), 25)
        AddToInventory("Ammo.RifleAmmo", 0)
        return true
    end    
    if val == "sniperammo" then

        local qty = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Ammo.SniperRifleAmmo"))
        if qty <= 0 then
            return false
        end

        Game.GetTransactionSystem():RemoveItem(Game.GetPlayer(), ItemID.FromTDBID("Ammo.SniperRifleAmmo"), 25)
        AddToInventory("Ammo.SniperRifleAmmo", 0)
        return true
    end    


    return false
end

function GetDirection(angle)
  return Vector4.RotateAxis(Game.GetPlayer():GetWorldForward(), Vector4.new(0, 0, 1, 0), angle / 180.0 * Pi())
end

function GetPosition(distance, angle)
  local pos = Game.GetPlayer():GetWorldPosition()
  local heading = GetDirection(angle)
  return Vector4.new(pos.x + (heading.x * distance), pos.y + (heading.y * distance), pos.z + heading.z, pos.w + heading.w)
end

function GetOrientation(angle)
  return EulerAngles.ToQuat(Vector4.ToRotation(GetDirection(angle)))
end

local spawntime = 0
local spamtime = 0

function Spawn(id, car, hostile)

    car = car or false
    hostile = hostile or true

    local player = Game.GetPlayer()
    local forward = player:GetWorldForward()
    local pos = player:GetWorldPosition()



    local recordID = TweakDBID.new(id)


   
	local entitySystem = Game.GetDynamicEntitySystem()
	local entitySpec = DynamicEntitySpec.new()

	entitySpec.persistState = false
	entitySpec.persistSpawn = false
	entitySpec.alwaysSpawned = false
	entitySpec.spawnInView = true

	entitySpec.recordID = recordID
	entitySpec.tags = { "CC_Enemy" }


	entitySpec.position = GetPosition(5.5, 0.0)
	entitySpec.orientation = GetOrientation(180.0)
	local entityID = entitySystem:CreateEntity(entitySpec)

    print("spawn requested")

	local timerfunc = function(timer)
        print("check called - " .. id)
		local entity = Game.FindEntityByID(entityID)
		if entity then
			Cron.Halt(timer)
            -- Force Hostile
            if car then
                if entity and entity.GetVehiclePS then
                    entity:GetVehiclePS():UnlockAllVehDoors()
                end
            else
                if hostile then
                    entity:GetAttitudeAgent():SetAttitudeTowards(player:GetAttitudeAgent(), 2)
                end
            end

		end
	end

    spawntime = 2.0

	Cron.Every(0.3, timerfunc)
end

local tier1 = {
        "Character.animals_bouncer1_melee1_baton_mb",
        "Character.animals_bouncer1_ranged1_kenshin_mb",
        "Character.cpz_animals_grunt1_melee1_fists_mb",
        "Character.animals_grunt1_ranged1_pulsar_mb",
        "Character.bls_se_tyger_claws_biker1_melee1_baseball_wa",
        "Character.dtn_tyger_claws_biker1_melee1_tireiron_ma",
        "Character.dtn_tyger_claws_gangster1_ranged1_nue_ma",
        "Character.cpz_maelstrom_grunt1_ranged1_copperhead_ma",
        "Character.kab_maelstrom_grunt1_melee1_wrench_wa",
        "Character.maelstrom_grunt1_melee1_knife_ma",
        "Character.lch_maelstrom_grunt1_ranged1_lexington_wa",
        "Character.gle_valentinos_grunt1_ranged1_nova_ma",
        "Character.rey_valentinos_grunt1_melee1_baseball_ma",
        "Character.arr_sixthstreet_hooligan_melee1_ironpipe_ma",
        "Character.rcr_sixthstreet_hooligan_ranged1_saratoga_wa",
        "Character.arr_scavenger_grunt1_ranged1_slaughtomatic_ma",
        "Character.bls_se_scavenger_grunt1_melee1_tireiron_ma",
        "Character.bou_scavenger_grunt1_melee1_fists_wa",
        "Character.kab_scavenger_grunt1_ranged1_nova_wa",
        "Character.wraiths_grunt1_melee1_ironpipe_ma",
        "Character.wraiths_grunt1_ranged1_nova_wa",
        "Character.bou_voodooboys_grunt1_ranged2_sidewinder_wa",
        "Character.ep1_voodooboys_grunt1coat_shotgun2_palica_ma",
        "Character.arasaka_security1_melee1_baton_ma",
        "Character.arr_arasaka_security1_ranged1_shingen_ma",
        "Character.arr_militech_ranger1_ranged1_saratoga_ma",
        "Character.militech_ranger1_ranged1_lexington_ma",
        "Character.cpz_kangtao_ranger1_ranged2_dian_ma",
        "Character.cpz_ncpd_constable_melee1_baton_ma",
        "Character.gle_ncpd_constable_ranged1_lexington_ma"
}
local tier2 = {
        "Character.animals_bouncer2_ranged2_burya_mb",
        "Character.animals_grunt2_hmelee2_hammer_wba_rare",
        "Character.cvi_animals_grunt2_ranged2_overture_mb",
        "Character.dtn_animals_grunt2_shotgun2_igla_wba_rare",
        "Character.dtn_tyger_claws_martial_fmelee2_katana_ma_rare",
        "Character.kab_tyger_claws_gangster2_ranged2_sidewinder_ma",
        "Character.cpz_maelstrom_grunt2_ranged2_ajax_wa",
        "Character.lch_maelstrom_fast_sniper2_grad_ma",
        "Character.maelstrom_android_android2_copperhead_ma",
        "Character.maelstrom_netrunner_netrunner2_lexington_ma",
	    "Character.maelstrom_techie_grenadier2_lexington_ma",
        "Character.arr_valentinos_grunt2_ranged2_overture_wa",
        "Character.rey_valentinos_grunt2_melee2_knife_wa",
        "Character.sixthstreet_prepers3_grenadier2_nova_ma_rare",
        "Character.sixthstreet_sniper2_sniper2_sor22_ma_rare",
        "Character.bou_scavenger_grunt2_melee2_pipewrench_ma",
        "Character.ep1_scavenger_netrunner2_netrunner2_nova_wa_rare",
        "Character.mon_scavenger_elite2_shotgun_tactician_ma",
        "Character.bls_se_wraiths_grunt2_melee2_crowbar_wa",
        "Character.bls_se_wraiths_android_android2_pulsar_ma",
        "Character.rcr_wraiths_ghost2_sniper2_achilles_ma_rare",
        "Character.bou_voodooboys_netrunner2_netrunner2_lexington_wa_rare",
        "Character.mon_voodooboys_grunt2coat_shotgun2_palica_wa",
        "Character.voodooboys_grunt1_ranged2_sidewinder_wa",
        "Character.arasaka_2020agent_fmelee2_katana_wa",
        "Character.arasaka_agent_franged2_yukimura_wa_rare",
        "Character.arasaka_tank2_gunner2_defender_mb_rarex",
        "Character.arr_militech_ranger2_ranged2_omaha_ma",
        "Character.bls_se_militech_enforcer2_shotgun2_tactician_mah_rare",
        "Character.bls_se_militech_tech_franged2_omaha_ma_rare",
        "Character.cpz_kangtao_soldier2_shotgun2_zhuo_mah_rare",
        "Character.gle_kangtao_android_android2_dian_ma",
        "Character.arr_ncpd_hwp_gunner2_defender_mb_rare",
        "Character.ncpd_biker_ranged2_omaha_ma",
        "Character.rcr_ncpd_police_ranged2_copperhead_ma" 
}
local tier3 = {
        "Character.animals_grunt3_gunner2_defender_mb_rare",
        "Character.cvi_animals_elite3_shotgun3_carnage_mba_elite",
        "Character.spr_animals_elite3_hmelee3_fists_mba_elite",
        "Character.bls_se_tyger_claws_biker3_shotgun2_tactician_wa",
        "Character.bls_se_tyger_claws_gangster3_ranged3_sidewinder_ma",
        "Character.dtn_tygerclaw_gangster3_netrunner_nue_wa_rare",
        "Character.jpn_tyger_claws_kunoichi_fmelee3_katana_wa_elite",
        "Character.jpn_tyger_claws_ozeki_hmelee3_kanabo_mb",
        "Character.maelstrom_fast_fmelee3_mantis_wa_elite",
        "Character.gang_retaliation_enemies_valentinos_ranged3_dual_ma_rare_gle_04",
        "Character.gle_valentinos_machete_hmelee3_machete_mb_elite",
        "Character.rey_valentinos_elite3_ranged3_dual_ma_elite",
        "Character.spr_valentinos_sniper_sniper3_grad_wa_elite",
        "Character.arr_sixthstreet_prepers3_grenadier2_nova_ma_rare",
        "Character.arr_sixthstreet_veteran3_ranged2_ajax_ma",
        "Character.rcr_sixthstreet_prepers3_shotgun3_carnage_ma_rare",
        "Character.bou_scavenger_butcher3_hmelee2_machete_mb_rare",
        "Character.cvi_scavenger_fast3_fmelee3_machete_wa_elite",
        "Character.ep1_scavenger_strong3_gunner2_defender_mb_rare",
        "Character.bls_se_wraiths_warrior3_ranged3_quasar_wa_rare",
        "Character.ina_03_wraiths_strong_gunner3_hmg_mb_elite",
        "Character.wraiths_strongarms_hmelee3_fists_mb_elite",
        "Character.hpark_voodooboys_netrunner3_netrunner3_quasar_wa_elite",
        "Character.arasaka_ninja_fmelee3_mantis_wa_elite",
        "Character.q108_arasaka_2020agent_ranged3_2020nue_ma",
        "Character.cpz_arasaka_cyborg_grenadier3_yukimura_ma_elite",
        "Character.cpz_arasaka_cyborg_fshotgun3_zhuo_ma_elite",
        "Character.bls_se_militech_soldier3_shotgun3_crusher_mah_elite",
        "Character.militech_drone_bombus_hard",
        "Character.militech_drone_wyvern_hard",
        "Character.gle_kangtao_officer_grenadier3_mah_elite",
        "Character.ncpd_police_shotgun3_crusher_mb_elite",
        "Character.ncpd_drone_wyvern_hard",
        "Character.maxtac_av_sniper_wa_elite",
        "Character.maxtac_rifle_wa_elite",
        "Character.maxtac_gunner_mb_elite"
}

function cc_spawncar(val)
    if spawntime > 0 then
        return false
    end

    if val == "delamain" then
        Spawn("Vehicle.v_delamain_taxi", true)
    end

    if val == "turbo" then
        Spawn("Vehicle.v_sport1_quadra_turbo_player", true)
    end

    if val == "porsche" then
        Spawn("Vehicle.v_sport2_porsche_911turbo_player", true)
    end

    if val == "av" then
        Spawn("Vehicle.av_militech_manticore", true)
    end

    if val == "basilisk" then
        Spawn("Vehicle.v_militech_basilisk", true)
    end

    if val == "emperor" then
        Spawn("Vehicle.v_standard3_chevalier_emperor_police", true)
    end

    if val == "hoon" then
        Spawn("Vehicle.v_sport2_quadra_type66_nomad_tribute", true)
    end
    
    if val == "hellhound" then
        Spawn("Vehicle.v_standard3_militech_hellhound_player", true)
    end       
    
    if val == "rayfield" then
        Spawn("Vehicle.v_sport1_rayfield_caliburn_02_player", true)
    end    

    if val == "mackinaw" then
        Spawn("Vehicle.v_standard3_thorton_mackinaw_player", true)
    end  
    
    if val == "akashita" then
        Spawn("Vehicle.v_sportbike1_yaiba_kusanagi_player", true)
    end
    
    if val == "archer" then
        Spawn("Vehicle.v_standard2_archer_hella_player", true)
    end       
    
    if val == "maimai" then
        Spawn("Vehicle.v_standard2_makigai_maimai_player", true)
    end    

    if val == "vato" then
        Spawn("Vehicle.v_sport2_villefort_alvarado_valentinos_player", true)
    end       


    if val == "police" then
        Spawn("Vehicle.v_standard2_villefort_cortes_police", true)
    end    
    if val == "fire" then
        Spawn("Vehicle.v_utility4_militech_behemoth_fire_truck", true)
    end    
    if val == "ambulance" then
        Spawn("Vehicle.ma_hey_spr_12_trauma_av_engine_on", true)
    end    
    if val == "taxi" then
        Spawn("Vehicle.v_standard2_villefort_cortes_taxi", true)
    end    

    show_message(viewer .. " spawned a vehicle")
    return true
end

function cc_spam(val)
    if spamtime > 0 then
        return false
    end

    if val == "car" then
        PreventionSystem.ShowMessage("Hello, V? We've been trying to reach you about your car's extended warranty.", 10.0)
    end
    if val == "fan" then
        PreventionSystem.ShowMessage("V? " .. viewer .. " here, big fan! Just wanted to say hello!", 10.0)
    end
    if val == "pizza" then
        PreventionSystem.ShowMessage("Uh, hi, yes. I'd like to order a large pepperoni pizza, extra cheese. And could I get that boneless?", 10.0)
    end
    if val == "irs" then
        PreventionSystem.ShowMessage("This is an urgent call from the IRS. A lawsuit has been filed against you. If you do not pay immediately, a warrant will be issued for your arrest.", 10.0)
    end
    if val == "lottery" then
        PreventionSystem.ShowMessage("Congratulations, you are a winner! To release your $10 million prize you are required to pay a 1% processing fee, please call to confirm your winnings.", 10.0)
    end
    if val == "police" then
        PreventionSystem.ShowMessage("This is officer Anna Hamill with the NCPD, you are under arrest. Please lie down on the ground now and submit to detainment.", 10.0)
    end

    spamtime = 5.0
    return true
end


function cc_spawn(val)
    if spawntime > 0 then
        return false
    end

    local flip = false
    if math.random(0, 1) == 0 then
        flip = true
    end

    if val == "tier1" then
        Spawn(tier1[math.random(#tier1)])
    end
    if val == "tier2" then
        Spawn(tier2[math.random(#tier2)])
    end
    if val == "tier3" then
        Spawn(tier3[math.random(#tier3)])
    end
    
    if val == "adam" then
        Spawn("Character.Smasher")
    end
    if val == "royce" then
        Spawn("Character.Royce")
    end
    if val == "sasquatch" then
        Spawn("Character.q110_animals_boss")
    end
    if val == "oda" then
        Spawn("Character.main_boss_oda")
    end
    if val == "placide" then
        Spawn("Character.Placide")
    end
    if val == "hugh" then
        Spawn("Character.mq025_razor")
    end
    if val == "zaria" then
        Spawn("Character.q001_scavenger_boss")
    end
    if val == "woodman" then
        Spawn("Character.Woodman")
    end

    if val == "baseball" then
        if flip then
            Spawn("Character.bls_se_tyger_claws_biker1_melee1_baseball_wa")
        else
            Spawn("Character.dtn_tyger_claws_biker1_melee1_baseball_ma")
        end
    end
    if val == "hammer" then
        if flip then
            Spawn("Character.nid_maelstrom_grunt2_melee2_hammer_wa")
        else
            Spawn("Character.nid_maelstrom_grunt2_melee2_hammer_ma")
        end
    end
    if val == "katana" then
        if flip then
            Spawn("Character.hil_arasaka_ninja_fmelee3_katana_wa_elite")
        else
            Spawn("Character.nok_arasaka_ninja_fmelee3_katana_ma_elite")
        end
    end
     if val == "shotgun" then
        if flip then
            Spawn("Character.cvi_voodooboys_grunt2coat_shotgun2_palica_wa")
        else
            Spawn("Character.cvi_voodooboys_grunt1coat_shotgun2_palica_ma")
        end
    end
    if val == "assault" then
        if flip then
            Spawn("Character.bou_kurtz_soldier1_ranged2_rifle_ma")
        else
            Spawn("Character.bou_kurtz_soldier1_ranged2_rifle_wa")
        end
    end
    if val == "sniper" then
        if flip then
            Spawn("Character.gle_valentinos_sniper_sniper3_grad_wa_elite")
        else
            Spawn("Character.nid_arasaka_sniper_sniper3_nekomata_ma_elite")
        end
    end
    if val == "revolver" then
        if flip then
            Spawn("Character.arr_sixthstreet_hooligan_ranged1_nova_wa")
        else
            Spawn("Character.arr_sixthstreet_hooligan_ranged1_nova_ma")
        end
    end  
    if val == "smg" then
        if flip then
            Spawn("Character.bls_se_wraiths_grunt1_ranged1_pulsar_wa")
        else
            Spawn("Character.bls_se_wraiths_grunt1_ranged1_pulsar_ma")
        end
    end   
    show_message(viewer .. " spawned an enemy")
    return true
end

function cc_explode(val)
    --SpawnExplosion(5)
    return true
end

function cc_telehome(val)
    local loc = nil
    local name = nil

    if val == "mega" then
        loc = {x = -1386.554688, y = 1271.295044, z = 123.064896, rot = -93}
        name = '[ WATSON - LITTLE CHINA ]\nV\'s APARTMENT  [ MEGABUILDING H10 ]'
    end
    if val == "glen" then
        loc = {x = -1524.962158, y = -969.364868, z = 86.970001, rot = -178}
        name = '[ HEYWOOD - THE GLEN ]\nV\'s APARTMENT';
    end
    if val == "north" then
        loc = {x = -1504.432861, y = 2227.191895, z = 22.231918, rot = 12}
        name = '[ WATSON - NORTHSIDE ]\nV\'s APARTMENT'; 
    end
    if val == "japan" then
        loc = {x = -784.456055, y = 978.770142, z = 28.209541, rot = 124}
        name = '[ WESTBROOK - JAPANTOWN ]\nV\'s APARTMENT';
    end
    if val == "corpo" then
        loc = {x = -1599.058105, y = 353.415619, z = 49.200005, rot = 78}
        name = '[ CITY CENTER - CORPO PLAZA ]\nV\'s APARTMENT';
    end
    if val == "mansion" then
        loc = {x = -1340.657349, y = 1188.979004, z = 115.007172, rot = -1}
        name = '[ WATSON - LITTLE CHINA ]\nV\'s MANSION  [ INSIDE ]';
    end    

    if loc == nil then return false end

    local auto = GameOptions.GetBool("SaveConfig", "AutoSaveEnabled")
    if auto then
        GameOptions.SetBool("SaveConfig", "AutoSaveEnabled", false)

        Cron.After(5.0, function()
            GameOptions.SetBool("SaveConfig", "AutoSaveEnabled", true)
        end)

    end

    Game.GetTeleportationFacility():Teleport(Game.GetPlayer(), Vector4.new(loc.x, loc.y, loc.z, 1), EulerAngles.new(0, 0, loc.rot))
    
    PreventionSystem.ShowMessage(name, 10.0) 
    show_message(viewer .. " teleported you")
    teletime = 5.0
    return true
end


function cc_teleshop(val)
    local loc = nil
    local name = nil

    if val == "drchrome" then
        loc = {x = -1245.325439, y = 1945.930908, z = 8.030479, rot = 0}
        name = "RIPPERDOC - DR. CHROME  [WATSON - KABUKI]"
    end

    if val == "fingers" then
        loc = {x = -573.507813, y = 795.048279, z = 24.906097, rot = 0}
        name = "RIPPERDOC - FINGERS M.D.  [WESTBROOK - JAPANTOWN]"
    end

    if val == "ironlead" then
        loc = {x = -1895.143433, y = 2729.943359, z = 7.449997, rot = 0}
        name = "GUN SHOP - IRON & LEAD  [WATSON - NORTHSIDE]"
    end

    if val == "ventura" then
        loc = {x = -1899.170654, y = -1019.690430, z = 7.676468, rot = 0}
        name = "GUN SHOP - VENTURA&SKYLINE VENDOR  [HEYWOOD - THE GLEN]"
    end

    if val == "sakura" then
        loc = {x = -682.614563, y = 1239.223755, z = 37.966957, rot = 0}
        name = "CLOTHING STORE - BLOSSOMING SAKURA CLOTHIER  [WESTBROOK - JAPANTOWN]"
    end

    if val == "appel" then
        loc = {x = -1575.944580, y = -282.437988, z = -4.425003, rot = 0}
        name = "CLOTHING STORE - APPEL DE PARIS  [CITY CENTER - CORPO PLAZA]"
    end

    if val == "chang" then
        loc = {x = -492.061035, y = 583.292725, z = 26.802223, rot = 0}
        name = "NETRUNNER - CHANG HOON NAM  [WESTBROOK - JAPANTOWN]"
    end

    if val == "coachfred" then
        loc = {x = -1430.860107, y = 1335.109497, z = 119.206131, rot = 0}
        name = "MELEE VENDOR - COACH FRED  [WATSON - LITTLE CHINA]"
    end

    if val == "dockspharma" then
        loc = {x = -1930.447875, y = 2741.377685, z = 10.449996, rot = 0}
        name = "PHARMACY - DOCKS PHARMACEUTICALS   [WATSON - NORTHSIDE]"
    end

    if val == "mallagra" then
        loc = {x = 428.308593, y = -1442.177734, z = 15.195770, rot = 0}
        name = "PHARMACY - MALLAGRA & MANZANITA DRUGS   [SANTO DOMINGO - RANCHO CORONADO]"
    end

    if loc == nil then return false end

    local auto = GameOptions.GetBool("SaveConfig", "AutoSaveEnabled")
    if auto then
        GameOptions.SetBool("SaveConfig", "AutoSaveEnabled", false)

        Cron.After(5.0, function()
            GameOptions.SetBool("SaveConfig", "AutoSaveEnabled", true)
        end)

    end

    Game.GetTeleportationFacility():Teleport(Game.GetPlayer(), Vector4.new(loc.x, loc.y, loc.z, 1), EulerAngles.new(0, 0, loc.rot))
    
    PreventionSystem.ShowMessage(name, 10.0) 
    show_message(viewer .. " teleported you")
    teletime = 5.0
    return true
end

function cc_teleclub(val)
    local loc = nil
    local name = nil

    if val == "hell" then
        loc = {x = -1941.699097, y = -43.114662, z = -1.532372, rot = 0}
        name = 'CLUB - 7TH HELL  [CITY CENTER - DOWNTOWN]'
    end
    if val == "after" then
        loc = {x = -1456.893433, y = 1038.277222, z = 16.825035, rot = 0}
        name = "CLUB - AFTERLIFE  [WATSON - LITTLE CHINA]"
    end
    if val == "clouds" then
        loc = {x = -652.481812, y = 790.145996, z = 128.252228, rot = 0}
        name = "CLUB - CLOUDS [INSIDE]  [WESTBROOK - JAPANTOWN]"
    end
    if val == "dark" then
        loc = {x = -346.081238, y = 221.274918, z = 191.086502, rot = 0}
        name = "CLUB - DARK MATTER [INSIDE]  [WESTBROOK - JAPANTOWN]"
    end
    if val == "lizzie" then
        loc = {x = -1207.988525, y = 1563.142090, z = 22.920128, rot = 0}
        name = "CLUB - LIZZIE'S BAR  [WATSON - KABUKI]"
    end
    if val == "riot" then
        loc = {x = -1639.360839, y = 1019.90295, z = 28.824333, rot = 0}
        name = "CLUB - RIOT  [INSIDE] [WATSON - LITTLE CHINA]"
    end    
    if val == "toten" then
        loc = {x = -1738.612061, y = 2213.224121, z = 90.204559, rot = 0}
        name = "CLUB - TOTENTANZ  [WATSON - NORTHSIDE]"
    end 
    if val == "atlantis" then
        loc = {x = -756.448852, y = 1074.70104, z = 62.005004, rot = 0}
        name = "CLUB - THE ATLANTIS  [WESTBROOK - JAPANTOWN]"
    end 
    if val == "coyote" then
        loc = {x = -1260.774536, y = -981.771790, z = 11.589195, rot = 0}
        name = "CLUB - EL COYOTE COJO  [HEYWOOD - THE GLEN]"
    end 
    
    if loc == nil then return false end

    local auto = GameOptions.GetBool("SaveConfig", "AutoSaveEnabled")
    if auto then
        GameOptions.SetBool("SaveConfig", "AutoSaveEnabled", false)

        Cron.After(5.0, function()
            GameOptions.SetBool("SaveConfig", "AutoSaveEnabled", true)
        end)

    end
    
    Game.GetTeleportationFacility():Teleport(Game.GetPlayer(), Vector4.new(loc.x, loc.y, loc.z, 1), EulerAngles.new(0, 0, loc.rot))
    
    PreventionSystem.ShowMessage(name, 10.0) 
    show_message(viewer .. " teleported you")
    teletime = 5.0
    return true
end

function cc_perkup(val)
    local AttPoints = 1;
    local PointType = gamedataDevelopmentPointType.Primary;
    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())

    local cur = DS:GetDevPoints(PointType)
    if cur > 20 then return false end

    DS:AddDevelopmentPoints(AttPoints, PointType)
    show_message(viewer .. " gave you a perk point")
    return true
end

function cc_perkdown(val)
    local AttPoints = -1;
    local PointType = gamedataDevelopmentPointType.Primary;
    local DS = PlayerDevelopmentSystem.GetInstance(Game.GetPlayer()):GetDevelopmentData(Game.GetPlayer())

    local cur = DS:GetDevPoints(PointType)
    if cur < 1 then return false end

    DS:AddDevelopmentPoints(AttPoints, PointType)
    show_message(viewer .. " took a perk point")
    return true
end

function cc_kill(val)
    Game.GetPlayer():Kill(Game.GetPlayer())
    show_message(viewer .. " killed you")
    return true
end

function AddToInventory(item, qty)
  local equip = EquipRequest.new()
  local recordID = ItemID.FromTDBID(TweakDBID.new(item))

  Game.GetTransactionSystem():GiveItem(Game.GetPlayer(), recordID, qty)
  equip.owner = Game.GetPlayer()
  Game.GetScriptableSystemsContainer():Get("EquipmentSystem"):QueueRequest(equip)
end

function cc_money(val)

    local del = tonumber(val)

    local money = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Items.money"))

    money = money + del

    if money > 10000000 then
        return false
    end

    AddToInventory("Items.money", del)
    show_message(viewer .. " gave you money")
    return true
end

function cc_tmoney(val)

    local del = tonumber(val)

    local money = Game.GetTransactionSystem():GetItemQuantity(Game.GetPlayer(), ItemID.FromTDBID("Items.money"))

    if money < del * 0.5 then
        return false
    end

    Game.GetTransactionSystem():RemoveItem(Game.GetPlayer(), ItemID.FromTDBID("Items.money"), del)
    show_message(viewer .. " took your money")
    return true
end

function cc_invul(val)
    if invul or ohko then
        return false
    end

    local time = tonumber(val)

    local player = Game.GetPlayer()
    local statPools = Game.GetStatPoolsSystem()
    local statsSys = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    oldhealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Health, false)
    invul = true

    Cron.After(time/1000.0, function()

        invul = false
        show_message("Your invulnerability wore off")

        local currentHealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Health, false)
        
        Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
            entityID,
            "Health",
            oldhealth - currentHealth,
            player,
            true,
            false
        )

    end)
    show_message(viewer .. " made you invulnerable")
    return true
end

function cc_ohko(val)
    if invul or ohko then
        return false
    end

    local time = tonumber(val)

    local player = Game.GetPlayer()
    local statPools = Game.GetStatPoolsSystem()
    local statsSys = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    oldhealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Health, false)
    ohko = true

    Cron.After(time/1000.0, function()

        ohko = false
        show_message("One Hit KO mode ended")
        
        local currentHealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Health, false)
        
        Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
            entityID,
            "Health",
            oldhealth - currentHealth,
            player,
            true,
            false
        )

    end)
        show_message(viewer .. " triggered one hit KO")
    return true
end

function cc_bunnyhop(val)
    if hop then
        return false
    end

    local time = tonumber(val)

    hop = true

    Cron.After(time/1000.0, function()
        hop = false
    end)
    show_message(viewer .. " triggered bunny hops")
    return true
end

function cc_wide(val)
    if oldfov > 0 then
        return false
    end

    local time = tonumber(val)

    local cam = Game.GetPlayer():GetFPPCameraComponent()
    oldfov = cam:GetFOV()
    cam:SetFOV(oldfov * 1.5)

    Cron.After(time/1000.0, function()

        local cam = Game.GetPlayer():GetFPPCameraComponent()
        cam:SetFOV(oldfov)
        oldfov = 0

    end)
        show_message(viewer .. " triggered wide camera")
    return true
end


function cc_narrow(val)
    if oldfov > 0 then
        return false
    end

    local time = tonumber(val)

    local cam = Game.GetPlayer():GetFPPCameraComponent()
    oldfov = cam:GetFOV()
    cam:SetFOV(oldfov * 0.5)

    Cron.After(time/1000.0, function()

        local cam = Game.GetPlayer():GetFPPCameraComponent()
        cam:SetFOV(oldfov)
        oldfov = 0

    end)
    show_message(viewer .. " triggered narrow camera")
    return true
end

function cc_nojump(val)
    if oldjump > 0 then
        return false
    end

    local time = tonumber(val)

    oldjump = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.JumpHeight, gameStatModifierType.Multiplier, 0.0)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        oldjump = 0

    end)
    show_message(viewer .. " disabled jumping")
    return true
end

function cc_lowjump(val)
    if oldjump > 0 then
        return false
    end

    local time = tonumber(val)

    oldjump = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.JumpHeight, gameStatModifierType.Multiplier, 0.5)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        oldjump = 0

    end)
    show_message(viewer .. " decreased your jump height")
    return true
end

function cc_highjump(val)
    if oldjump > 0 then
        return false
    end

    local time = tonumber(val)

    oldjump = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.JumpHeight, gameStatModifierType.Multiplier, 4.0)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    local FallMod = RPGManager.CreateStatModifier(gamedataStatType.FallDamageReduction, gameStatModifierType.Additive, 100)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), FallMod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), FallMod)        
        oldjump = 0

    end)
    show_message(viewer .. " increased your jump height")    
    return true
end

function cc_moonjump(val)
    if oldjump > 0 then
        return false
    end

    local time = tonumber(val)

    oldjump = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.JumpHeight, gameStatModifierType.Multiplier, 16.0)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    local FallMod = RPGManager.CreateStatModifier(gamedataStatType.FallDamageReduction, gameStatModifierType.Additive, 100)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), FallMod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), FallMod)        
        oldjump = 0

    end)
    show_message(viewer .. " increased your jump height")
    return true
end

function cc_slow(val)
    if oldspeed > 0 then
        return false
    end

    local time = tonumber(val)

    oldspeed = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.MaxSpeed, gameStatModifierType.Multiplier, 0.5)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        oldspeed = 0

    end)
    show_message(viewer .. " decreased your movement speed")
    return true
end

function cc_uslow(val)
    if oldspeed > 0 then
        return false
    end

    local time = tonumber(val)

    oldspeed = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.MaxSpeed, gameStatModifierType.Multiplier, 0.25)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        oldspeed = 0

    end)
    show_message(viewer .. " decreased your movement speed")
    return true
end

function cc_fast(val)
    if oldspeed > 0 then
        return false
    end

    local time = tonumber(val)

    oldspeed = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.MaxSpeed, gameStatModifierType.Multiplier, 3.0)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        oldspeed = 0

    end)
    show_message(viewer .. " increased your movement speed")
    return true
end

function cc_hyper(val)
    if oldspeed > 0 then
        return false
    end

    local time = tonumber(val)

    oldspeed = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.MaxSpeed, gameStatModifierType.Multiplier, 6.0)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        oldspeed = 0

    end)
    show_message(viewer .. " increased your movement speed")
    return true
end

function cc_freeze(val)
    if oldspeed > 0 then
        return false
    end

    local time = tonumber(val)

    oldspeed = 1.0

    local Mod = RPGManager.CreateStatModifier(gamedataStatType.MaxSpeed, gameStatModifierType.Multiplier, 0)
    Game.GetStatsSystem():AddModifier(Game.GetPlayer():GetEntityID(), Mod)

    Cron.After(time/1000.0, function()

        Game.GetStatsSystem():RemoveModifier(Game.GetPlayer():GetEntityID(), Mod)
        oldspeed = 0

    end)
    show_message(viewer .. " froze you")
    return true
end

function cc_infstam(val)
    if infstam or nostam then
        return false
    end

    local time = tonumber(val)

    infstam = true

    Cron.After(time/1000.0, function()

        infstam = false

    end)
    show_message(viewer .. " gave you infinite stamina")
    return true
end

function cc_nostam(val)
    if infstam or nostam then
        return false
    end

    local time = tonumber(val)

    nostam = true

    Cron.After(time/1000.0, function()

        nostam = false

    end)
    show_message(viewer .. " disabled your stamina")
    return true
end

function cc_heal(val)

    if invul or ohko then
        return false
    end

    local del = tonumber(val) / 100.0

    local player = Game.GetPlayer()
    local statPools = Game.GetStatPoolsSystem()
    local statsSys = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    local currentHealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Health, false)
    local maxHealth = statsSys:GetStatValue(entityID, gamedataStatType.Health)

    if currentHealth >= maxHealth then
        return false
    end

    local newHealth = currentHealth + del * maxHealth

    if newHealth > maxHealth then
        newHealth = maxHealth
    end

    Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
        entityID,
        "Health",
        del * maxHealth,
        player,
        true,
        false
    )
    show_message(viewer .. " healed you")
    return true
end

function cc_damage(val)

    if invul or ohko then
        return false
    end

    local del = tonumber(val) / 100.0


    local player = Game.GetPlayer()
    local statPools = Game.GetStatPoolsSystem()
    local statsSys = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    local currentHealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Health, false)
    local maxHealth = statsSys:GetStatValue(entityID, gamedataStatType.Health)

    if currentHealth <= 1 then
        return false
    end

    local newHealth = currentHealth - del * maxHealth

    if newHealth < 1 then
        newHealth = 1
    end
    
    Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
        entityID,
        "Health",
        -del * maxHealth,
        player,
        true,
        false
    )
    show_message(viewer .. " damaged you")
    return true
end

function cc_stamup(val)
    if infstam or nostam then
        return false
    end

    local del = tonumber(val) / 100.0

    local player = Game.GetPlayer()
    local statPools = Game.GetStatPoolsSystem()
    local statsSys = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    local currentHealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Stamina, false)
    local maxHealth = statsSys:GetStatValue(entityID, gamedataStatType.Stamina)

    if currentHealth >= maxHealth then
        return false
    end

    local newHealth = currentHealth + del * maxHealth

    if newHealth > maxHealth then
        newHealth = maxHealth
    end

    Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
        entityID,
        "Stamina",
        del * maxHealth,
        player,
        true,
        false
    )
    show_message(viewer .. " filled your stamina")
    return true
end

function cc_stamdown(val)
    if infstam or nostam then
        return false
    end

    local del = tonumber(val) / 100.0


    local player = Game.GetPlayer()
    local statPools = Game.GetStatPoolsSystem()
    local statsSys = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    local currentHealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Stamina, false)
    local maxHealth = statsSys:GetStatValue(entityID, gamedataStatType.Stamina)

    if currentHealth <= 1 then
        return false
    end

    local newHealth = currentHealth - del * maxHealth

    if newHealth < 1 then
        newHealth = 1
    end

    Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
        entityID,
        "Stamina",
        -del * maxHealth,
        player,
        true,
        false
    )
    show_message(viewer .. " emptied your stamina")
    return true
end

local connected = false


local function OnConnection(status)
    if status ~= 0 then
        print("Failed to connect to server.")

        connected = false
        Cron.After(5.0, function()
            socket:Connect("127.0.0.1", 51337)
        end)


        return
    end
    print("Ready to read/write commands.")
    connected = true
end

local function OnDisconnection()
    connected = false
    print("Connection is closed.")

    Cron.After(5.0, function()
        socket:Connect("127.0.0.1", 51337)
    end)
end

local function OnError()
	print("Cannot send command: too many failed attempts.")
end

local messages = {}
local deltime = 0

function show_message(txt)
    table.insert(messages, txt)
    if deltime == 0 then
        deltime = 3.0
    end
end

local isOverlayOpen = false

registerForEvent("onOverlayOpen", function()
    isOverlayOpen = true
end)

registerForEvent("onOverlayClose", function()
    isOverlayOpen = false
end)

registerForEvent("onDraw", function()
    if connected and (#messages > 0 or isOverlayOpen) then
        ImGui.SetNextWindowBgAlpha(0.0)
        ImGui.Begin("Crowd Control Log", ImGuiWindowFlags.NoBackground + ImGuiWindowFlags.NoScrollbar)

        for index, value in ipairs(messages) do
            ImGui.Text(value)
        end

        ImGui.End()
    end
end)

registerForEvent('onInit', function()

    local RedSocket = GetMod("RedSocket")

    if RedSocket == nil then
        print("RedSocket is not installed.")
        return
    end

    socket = RedSocket.createSocket()

    socket:RegisterListener(OnCommand,
                        OnConnection,
                        OnDisconnection,
                        OnError)

    socket:Connect("127.0.0.1", 51337)

end)

registerForEvent('onUpdate', function(delta)
    Cron.Update(delta)

    local currentTime = Game.GetTimeSystem():GetGameTime():GetSeconds()
    frozen = (currentTime == lasttime)
    lasttime = currentTime
    
    if isTimeFrozen then return end -- Pause script

    if teletime > 0 then
        teletime = teletime - delta
        if teletime < 0 then
            teletime = 0
        end
    end

    if spawntime > 0 then
        spawntime = spawntime - delta
        if spawntime < 0 then
            spawntime = 0
        end
    end

    if spamtime > 0 then
        spamtime = spamtime - delta
        if spamtime < 0 then
            spamtime = 0
        end
    end

    if deltime > 0 then
        deltime = deltime - delta
        if deltime <= 0 then
            deltime = 0
            table.remove(messages, 1)
            if #messages > 0 then
                deltime = 2.0
            end
        end
    end

    local player = Game.GetPlayer()
    local statPools = Game.GetStatPoolsSystem()
    local statsSys = Game.GetStatsSystem()
    local entityID = player:GetEntityID()

    if invul then
        local maxHealth = statsSys:GetStatValue(entityID, gamedataStatType.Health)

        Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
            entityID,
            "Health",
            maxHealth,
            player,
            true,
            false
        )
    end

    if ohko then
        local currentHealth = statPools:GetStatPoolValue(entityID, gamedataStatPoolType.Health, false)

        if currentHealth > 1 then

            Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
                entityID,
                "Health",
                1 - currentHealth,
                player,
                true,
                false
            )
        end
    end    

    if infstam then
        local maxHealth = statsSys:GetStatValue(entityID, gamedataStatType.Stamina)

        Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
            entityID,
            "Stamina",
            maxHealth,
            player,
            true,
            false
        )
    end

    if nostam then
        local maxHealth = statsSys:GetStatValue(entityID, gamedataStatType.Stamina)

        Game.GetStatPoolsSystem():RequestChangingStatPoolValue(
            entityID,
            "Stamina",
            -maxHealth,
            player,
            true,
            false
        )
    end    

end)




