local Badge = require "widgets/badge"
local easing = require "easing"
local MakePlayerCharacter = require "prefabs/player_common"
local Text = require "widgets/text"
local ImageButton = require "widgets/imagebutton"
local RivenScreen = require "screens/rivenscreen"
local ModsScreen = require "screens/modsscreen"
local function testpoint (x,y,z)
    if IsDLCEnabled and CAPY_DLC and IsDLCEnabled(CAPY_DLC) then
        return true
    end
    local ground = GetWorld()
    local tile = ground.Map:GetTileAtPoint(x, y, z)
    return tile ~= GROUND.IMPASSABLE
end
local assets = {
        Asset( "ANIM", "anim/player_basic.zip" ),
        Asset( "ANIM", "anim/player_idles_shiver.zip" ),
        Asset( "ANIM", "anim/player_actions.zip" ),
        Asset( "ANIM", "anim/player_actions_axe.zip" ),
        Asset( "ANIM", "anim/player_actions_pickaxe.zip" ),
        Asset( "ANIM", "anim/player_actions_shovel.zip" ),
        Asset( "ANIM", "anim/player_actions_blowdart.zip" ),
        Asset( "ANIM", "anim/player_actions_eat.zip" ),
        Asset( "ANIM", "anim/player_actions_item.zip" ),
        Asset( "ANIM", "anim/player_actions_uniqueitem.zip" ),
        Asset( "ANIM", "anim/player_actions_bugnet.zip" ),
        Asset( "ANIM", "anim/player_actions_fishing.zip" ),
        Asset( "ANIM", "anim/player_actions_boomerang.zip" ),
        Asset( "ANIM", "anim/player_bush_hat.zip" ),
        Asset( "ANIM", "anim/player_attacks.zip" ),
        Asset( "ANIM", "anim/player_idles.zip" ),
        Asset( "ANIM", "anim/player_rebirth.zip" ),
        Asset( "ANIM", "anim/player_jump.zip" ),
        Asset( "ANIM", "anim/player_amulet_resurrect.zip" ),
        Asset( "ANIM", "anim/player_teleport.zip" ),
        Asset( "ANIM", "anim/wilson_fx.zip" ),
        Asset( "ANIM", "anim/player_one_man_band.zip" ),
        Asset( "ANIM", "anim/shadow_hands.zip" ),
        Asset( "SOUND", "sound/sfx.fsb" ),
        Asset( "SOUND", "sound/wilson.fsb" ),
        Asset( "ANIM", "anim/riven.zip" ),
        Asset( "ANIM", "anim/rivenorigin.zip" ),
        Asset( "ANIM", "anim/xxxmagic_riven.zip" ),
        Asset( "IMAGE", "images/riventab.tex"),
        Asset( "ATLAS", "images/riventab.xml"),
        Asset("ATLAS", "images/inventoryimages/rivensword.xml"),  
        Asset("IMAGE", "images/inventoryimages/rivensword.tex"),
}
local prefabs = {}
local start_inv = {
    "rivensoulballwhite"
}

local attackspeedbase = TUNING.WILSON_ATTACK_PERIOD or 0.5
local walkspeed =TUNING.WILSON_WALK_SPEED or 4
local runspeed =TUNING.WILSON_RUN_SPEED or 6
local raise = 1.4
local hungeryrate = TUNING.WILSON_HUNGER_RATE or 75/(30*16)
local WCD = 11

local RCD = 130
local hungeryratespeed =1

local attack = 1.00
local defend = 0.00
local cdtime = 1
local baseexp = 15
local baseexpclone = baseexp
local charhealth = 113
local charhunger = 100
local charsanity = 150
local afraid = 1
local attackspeed = 1
local charspeed = 1
local charcrit = 0.02
local heal = 0.009
local attackraise = 0.002
local defendraise = 0.001
local cdtimeraise = 0.01
local charhealthraise = charhealth*0.02
local charhungerraise = charhunger*0.02
local charsanityraise = charsanity*0.02
local attackspeedraise = 0.003
local charspeedraise = 0.006
local charcritraise = 0.002
local healspeed = 0.0003
local function CreateLabel(inst, parent)
    inst.persists = false
    if not inst.Transform then
        inst.entity:AddTransform()
    end
    inst.Transform:SetPosition( parent.Transform:GetWorldPosition() )
    return inst
end
local function mylevel()
    if GetPlayer() and GetPlayer().levelvaluenum then
        return GetPlayer().levelvaluenum
    else
        return 0
    end
end
local function getrandomposition()
    local ground = GetWorld()
    local centers = {}
    for i,node in ipairs(ground.topology.nodes) do
        local tile = GetWorld().Map:GetTileAtPoint(node.x, 0, node.y)
        if tile and tile ~= GROUND.IMPASSABLE then
            table.insert(centers, {x = node.x, z = node.y})
        end
    end
    if #centers > 0 then
        local pos = centers[math.random(#centers)]
        return Point(pos.x, 0, pos.z)
    else
        return GetPlayer():GetPosition()
    end
end
local function destoryq(inst)
    if inst.qrectask then
        inst.qrectask:Cancel()
        inst.qrectask = nil
    end
end
local function qtimeout(inst)
    inst.destoryq(inst)
    inst.qrectask=inst:DoTaskInTime(5, function()
        inst.removealltag(inst)
        inst.destoryq(inst)
    end)
end

local function nocasting(inst)
    return not (inst:HasTag("skillq") or inst:HasTag("skillw") or inst:HasTag("skille") or inst:HasTag("skillr"))
end
local function removealltag(inst)
    if inst:HasTag("qbuffon") then
        inst:RemoveTag("qbuffon")
    end
    if inst:HasTag("wbuffon") then
        inst:RemoveTag("wbuffon")
    end
    if inst:HasTag("ebuffon") then
        inst:RemoveTag("ebuffon")
    end
    if inst:HasTag("rbuffon") then
        inst:RemoveTag("rbuffon")
    end
end
local function CreateDamageIndicator(parent,str,r,g,b)
    local posy = 4
    local inst = CreateLabel(CreateEntity(), parent)
    local label = inst.entity:AddLabel()
    label:SetFont(NUMBERFONT)
    label:SetFontSize(50)
    label:SetPos(0, posy, 0)
    if not r then
        r=0.7
    end
    if not g then
        g=0
    end
    if not b then
        b=0
    end
    if not str then
        str="Critical"
    end
    label:SetColour(r, g, b)
    label:SetText(str) 
    label:Enable(true)
    inst:StartThread(function()
        local label = inst.Label
        local t = 0
        local t_max = 1.0
        local dt = 0.01
        local y = posy
        local dy = 0.05
        local ddy = 0.0
        local side = (math.random() * (1.6 - 0.8) + 0.8) * (math.random() >= 0.5 and -1 or 1)
        local dside = 0.0
        local ddside = 0.0
        while inst:IsValid() and t < t_max do
            ddy = 0.003 * (math.random() * 0.5 + 0.5)
            dy = dy + ddy
            y = y + dy
            ddside = -side * math.random()*0.15
            dside = dside + ddside
            side = side + dside
            local headingtarget = 45 % 180
            if headingtarget == 0 then 
                label:SetPos(0, y, side)  
            elseif headingtarget == 45 then
                label:SetPos(side, y, -side)    
            elseif headingtarget == 90 then
                label:SetPos(side, y, 0)       
            elseif headingtarget == 135 then
                label:SetPos(side, y, side)   
            end
            t = t + dt
            label:SetFontSize(70 * math.sqrt(1 - t / t_max))
            Sleep(dt)
        end

        inst:Remove()
    end)
    return inst
end
local function setbaseattr(inst,tmplevel,tmpvaild,myweapon)
    local greengem=0
    local yellowgem=0
    local bluegem=0
    local orangegem=0
    local purplegem=0
    local valid=tmpvaild
    local weapon
    if valid and myweapon then
        weapon = myweapon
    else
        weapon = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) 
    end
    if not valid then
        if weapon and weapon:HasTag("rivenweapon") then 
            valid=1
        else
            valid=0
        end
    end
    local period=1
    if valid==1 and weapon then
        greengem=weapon.greengem
        yellowgem=weapon.yellowgem
        bluegem=weapon.bluegem
        orangegem=weapon.orangegem
        purplegem=weapon.purplegem
        if weapon.period then
            period=weapon.period
        end 
    end
    if inst.components.xxxmagic_riven.armor==0 then 
        if inst.components.health.SetAbsorptionAmount then
            inst.components.health:SetAbsorptionAmount(defend+(tmplevel+bluegem*valid*2)*defendraise)
        else 
            inst.components.health.absorb=defend+(tmplevel+bluegem*valid*2)*defendraise
        end
    end

    inst.absorb=defend+tmplevel*defendraise
    inst.components.sanity.night_drain_mult = afraid
    inst.components.sanity.neg_aura_mult = afraid
    inst.components.hunger.hungerrate = hungeryrate *hungeryratespeed
    inst.components.combat.damagemultiplier = attack+tmplevel*attackraise 
    if inst.components.combat.AddDamageModifier then
        inst.components.combat:AddDamageModifier("riven", attack+tmplevel*attackraise-1)
    end
    inst.charcritmulti=inst.components.combat.damagemultiplier
    inst.components.combat.min_attack_period = attackspeedbase*(attackspeed - tmplevel*attackspeedraise)*period
    inst.components.locomotor.walkspeed = walkspeed*(charspeed+(tmplevel+yellowgem*valid*2)*charspeedraise)
    inst.components.locomotor.runspeed = runspeed*(charspeed+(tmplevel+yellowgem*valid*2)*charspeedraise)
    inst.walkspeedback = inst.components.locomotor.walkspeed
    inst.runspeedback = inst.components.locomotor.runspeed
    inst.cdtime = cdtime - (tmplevel+purplegem*valid*2)*cdtimeraise
    inst.charcrit = charcrit + (tmplevel+orangegem*valid*2)*charcritraise
    inst.components.health:StartRegen((heal+(healspeed*(tmplevel+greengem*valid*2)))*4, 4)
end
local function setattr(inst,update)
    local tmplevel = inst.levelvaluenum -1
    if update then
        local curhealth= inst.components.health.currenthealth
        local curhunger= inst.components.hunger.current
        local cursanity= inst.components.sanity.current
        inst.components.health:SetMaxHealth(charhealth+tmplevel*charhealthraise)
        inst.components.hunger:SetMax(charhunger+tmplevel*charhungerraise)
        inst.components.sanity:SetMax(charsanity+tmplevel*charsanityraise)
        inst.components.health.currenthealth=curhealth+charhealthraise
        inst.components.hunger.current=curhunger+charhungerraise
        inst.components.sanity.current=cursanity+charsanityraise
        inst.components.health:DoDelta(0)
        inst.components.hunger:DoDelta(0)
        inst.components.sanity:DoDelta(0)
    end
    setbaseattr(inst,tmplevel)
end
local function SetHUDState(inst)
  if inst.HUD then
        inst.HUD.jinenglan_riven = inst.HUD.under_root:AddChild(Image("images/jinenglan_riven.xml", "jinenglan_riven.tex"))
        inst.HUD.jinenglan_riven:SetVRegPoint(ANCHOR_BOTTOM)
        inst.HUD.jinenglan_riven:SetHRegPoint(ANCHOR_LEFT)
        inst.HUD.jinenglan_riven:SetVAnchor(ANCHOR_BOTTOM)
        inst.HUD.jinenglan_riven:SetHAnchor(ANCHOR_LEFT)
        inst.HUD.jinenglan_riven:SetScaleMode(SCALEMODE_FIXEDSCREEN_NONDYNAMIC)
        inst.HUD.jinenglan_riven:SetClickable(true)
        inst.levelvalue = inst.HUD.jinenglan_riven:AddChild(Text(BODYTEXTFONT, 40))
        inst.levelvalue:SetHAlign(ANCHOR_MIDDLE)
        inst.levelvalue:SetHAnchor(ANCHOR_LEFT)
        inst.levelvalue:SetPosition(120,105,0)
        inst.levelvalue:SetString(string.format("lv:%d",inst.mylevel()))
        inst.levelvalue:SetColour(0, 0.5, 0, 1)
        local hehe = GetPlayer().HUD.controls.bottomright_root:AddChild(ImageButton("images/selectscreen_portraits/riven.xml", "riven.tex"))
        hehe:SetPosition(-60,160,0)
        hehe:SetScale(0.4)
        hehe:SetOnClick(function ()
            TheFrontEnd:PushScreen(RivenScreen())
        end)
        hehe:SetTooltip("Attribute")
        inst.expvalue = inst.HUD.jinenglan_riven:AddChild(Text(BODYTEXTFONT, 25))
        inst.expvalue:SetHAlign(ANCHOR_MIDDLE)
        inst.expvalue:SetHAnchor(ANCHOR_LEFT)
        inst.expvalue:SetPosition(120,80,0)
        inst.expvalue:SetString(string.format("exp:%d/%d",inst.expvaluenum,baseexp))
        inst.expvalue:SetColour(0.5, 0.5, 0, 1)
  end
end

local MagicBadge = Class(Badge, function(self, owner)
    Badge._ctor(self, "beaver_meter", owner)
end)

local function calculateAttribute(inst)
    baseexp=baseexpclone
    for i=1,inst.mylevel()-1 do
        baseexp=math.ceil(baseexp*raise)
    end
    if inst.expvalue and inst.levelvalue then
        inst.expvalue:SetString(string.format("exp:%d/%d",inst.expvaluenum,baseexp))
        inst.levelvalue:SetString(string.format("lv:%d",inst.mylevel()))
    end
end

local function refreshlevel(inst)
    local leveluped = false
    while inst.mylevel()<18 and inst.expvaluenum>=baseexp do
        inst.expvaluenum=inst.expvaluenum-baseexp 
        inst.levelvaluenum=inst.mylevel()+1 
        leveluped = true
        baseexp=baseexpclone
        for i=1,inst.mylevel()-1 do
            baseexp=math.ceil(baseexp*raise)
        end
    end

    if inst.mylevel()>=18 then
        inst.expvaluenum=0
    end

    if leveluped then
        local fx2=shitswap("statue_transition")
        if not fx2.components.highlight then
            fx2:AddComponent("highlight")
        end
        fx2.components.highlight:SetAddColour(Vector3(0,.5,1))
        fx2.Transform:SetScale(2, 2, 2)
        fx2.Transform:SetPosition(inst:GetPosition():Get())
        local fx=shitswap("explode_small")
        if not fx.components.highlight then
            fx:AddComponent("highlight")
        end
        fx.components.highlight:SetAddColour(Vector3(.5,1,1))
        fx.Transform:SetScale(2, 2, 2)
        fx.Transform:SetPosition(inst:GetPosition():Get())
        calculateAttribute(inst)
        setattr(inst,true)
    end
end


local function onkill(inst, data)
    if data and data.cause and (data.cause == inst.prefab or data.cause == "rivensoulball" or data.cause == "rivenporo" )
        and not data.inst:HasTag("prey") 
        and not data.inst:HasTag("veggie") 
        and not data.inst:HasTag("structure") 
        and not data.inst:HasTag("mypet") 
        and inst.components.xxxmagic_riven
        and inst.mylevel()<=18
        then
        if data.inst:HasTag(TUNING.RIVENENEMY) then
            inst.killmember=inst.killmember+1
        end

        inst.components.xxxmagic_riven:DoDelta(1)
        local exp=1
        if data.inst.components.health then
            exp=exp*data.inst.components.health.maxhealth
        end
        local expmu=1
        if TUNING.RIVEN_ENOMOUS_MONSTER ==2 then
            expmu=2
        elseif TUNING.RIVEN_ENOMOUS_MONSTER ==1 then
            expmu=1
        else
            expmu=0.5
        end
        if data.inst.components.combat then
            exp=math.floor(exp*data.inst.components.combat.defaultdamage*data.inst.components.combat.playerdamagepercent/1000)*expmu
        end
        if inst.mylevel()<18 then
            inst.expvaluenum=inst.expvaluenum+exp
            inst.expvalue:SetString(string.format("exp:%d/%d",inst.expvaluenum,baseexp))
            refreshlevel(inst)
        end
    end
end

local function OnAttacked(inst, data)
    local target=data.attacker
    for k,v in pairs(inst.components.leader.followers) do
        if  (k:HasTag("mypet"))
            and not (k.components.health ~= nil and
                     k.components.health:IsDead())  
            and k.components.combat:CanTarget(target)
            then
            k.components.combat:SetTarget(target)
        end
    end
    if target and inst.components.combat:CanTarget(target) and not target:HasTag(inst.belongtowhich) then
        inst.components.combat:ShareTarget(target, 30, function(dude)
            return dude:HasTag(inst.belongtowhich)
                   and not dude.components.health:IsDead()
        end, 10)
    end
end

local function onattackother(inst, data)
    local v = data.target

    local energy=1
    if inst.components.xxxmagic_riven.current>25 then
        inst.components.xxxmagic_riven:DoDelta(-15)
        energy=1.3
    end
    if inst:HasTag("rpre") then
        energy=energy*1.5
    end

    if v and inst.components.combat and v.components.combat and v.components.health and not v.components.health:IsDead() and math.random() < inst.charcrit then
        inst.components.talker:Say("Crit!")
        CreateDamageIndicator(v)
        inst.components.combat.damagemultiplier = inst.charcritmulti*2*energy 
        if inst.components.combat.AddDamageModifier then
            inst.components.combat:AddDamageModifier("riven", inst.charcritmulti*2*energy-1)
        end
    else
        inst.components.combat.damagemultiplier = inst.charcritmulti*energy
        if inst.components.combat.AddDamageModifier then
            inst.components.combat:AddDamageModifier("riven", inst.charcritmulti*energy-1)
        end
    end
    for k,m in pairs(inst.components.leader.followers) do
        if  (k:HasTag("mypet"))
            and not (k.components.health ~= nil and
                     k.components.health:IsDead())  
            and k.components.combat:CanTarget(v)
            then
            k.components.combat:SetTarget(v)
        end
    end
end

local function onpreload(inst, data)
    if data then
        if data.killmember then
            inst.killmember = data.killmember
        else
            inst.killmember = 0
        end
        if data.started then
            inst.started = data.started
        end
        
        if data.deathtime then
            inst.deathtime = data.deathtime
        else
            inst.deathtime = 0
        end
        if data.money then
            inst.money = data.money
        else
            inst.money = 0
        end
        if data.xxxmagic_riven then
            inst.components.xxxmagic_riven.current = data.xxxmagic_riven
        else
            inst.components.xxxmagic_riven.current = 0
        end
        if data.switchtoboss1 then
            inst.switchtoboss1 = data.switchtoboss1
        else
            inst.switchtoboss1 = false 
        end

        if data.expvaluenum then
            inst.expvaluenum = data.expvaluenum
        else
            inst.expvaluenum = 0 
        end

        if data.levelvaluenum and data.levelvaluenum<18 then
            inst.levelvaluenum = data.levelvaluenum
        elseif not data.levelvaluenum then 
            inst.levelvaluenum = 1 
        elseif data.levelvaluenum>=18 then
            inst.levelvaluenum=18
            inst.expvaluenum = 0 
        else
            inst.levelvaluenum = 1 
        end
        setattr(inst,true)
    end
end

local function onsave(inst, data)
    if inst.components.xxxmagic_riven and inst.components.xxxmagic_riven.current then
        data.xxxmagic_riven = inst.components.xxxmagic_riven.current
    else
        data.xxxmagic_riven = 0 
    end

    if inst.started then
        data.started=inst.started
    end

    if inst.killmember then
        data.killmember=inst.killmember
    else
        data.killmember=0
    end
    if inst.deathtime then
        data.deathtime=inst.deathtime
    else
        data.deathtime=0
    end
    if inst.money then
        data.money=inst.money
    else
        data.money=0
    end

    if inst.expvaluenum then
        data.expvaluenum=inst.expvaluenum
    else
        data.expvaluenum=0
    end
    if inst.switchtoboss1 then
        data.switchtoboss1=inst.switchtoboss1
    else
        data.switchtoboss1=false
    end

    if not inst.mylevel() then
        data.levelvaluenum=1
    elseif inst.mylevel()<18 then
        data.levelvaluenum=inst.mylevel()
    else
        data.levelvaluenum=18
        data.expvaluenum=0
    end
end
local fn = function(inst)
    RECIPETABS['RIVENTABS'] = {str = STRINGS.TABS.RIVENTABS, sort=328, icon = "riventab.tex", icon_atlas = "images/riventab.xml"}
    if Prefabs.yiyu then
        if not RECIPETABS.YIYUTAB then
            RECIPETABS.YIYUTAB = {str = "YIYUTAB", sort=999, icon = "yiyutab.tex", icon_atlas = "images/yiyutabs/yiyutab.xml"}
        end
    end
    if Prefabs.sari then
        if not RECIPETABS.SARITAB then
            RECIPETABS.SARITAB = {str = "SARITAB", sort=999, icon = "saritab.tex", icon_atlas = "images/saritabs/saritab.xml"}
        end
    end
    TUNING.RIVENALLP = GetActiveCharacterList()
    for i = 1, #TUNING.RIVENALLP do 
        if TUNING.RIVENALLP[i] then
            table.insert(assets, Asset( "ANIM", string.format("anim/%s.zip",TUNING.RIVENALLP[i])))
        end
    end 
    inst.killmember=0
    inst.deathtime=0
    inst.mylevel=mylevel
    inst.refreshlevel=refreshlevel
    inst.belongtowhich = TUNING.RIVENBELONG
    inst.CreateDamageIndicator=CreateDamageIndicator
    if TUNING.RIVEN_SKIN==2 then
        inst.AnimState:SetBuild("riven")
    else
        inst.AnimState:SetBuild("rivenorigin")
    end
    inst.changecdtimes=1
    inst.probtimes=1
    if TUNING.RIVEN_ENOMOUS_MONSTER==2 then
        inst.probtimes=10
    elseif TUNING.RIVEN_ENOMOUS_MONSTER==1 then
        inst.probtimes=1
    else
        inst.probtimes=0
    end

    if TUNING.RIVEN_ENOMOUS_MONSTER~=0 then
        inst.switchtoboss1 = false
        inst.GetPassedHalfDay = function ()
            return GetClock().numcycles 
        end
        inst.kyd=function()
            if inst.GetPassedHalfDay() % 9 == 6 then     
                inst.switchtoboss1 = true   
            end
            if inst.GetPassedHalfDay() % 9 >=6 and inst.switchtoboss1 == true and not inst.sumtask then
                inst.components.talker:Say(" 30s  until  minions  spawn! ")
                inst.sumtask=inst:DoTaskInTime(60+math.random(60), function() 
                    if inst.sumtask then
                        inst.sumtask:Cancel()
                        inst.sumtask=nil
                    end
                end)
            end
            if inst.GetPassedHalfDay() % 9 == 7 and TUNING.TOTAL_DAY_TIME * (1 - GetClock():GetNormTime())<280 then
                if inst.switchtoboss1 == true then
                    shitswap("lightning")
                    inst.components.talker:Say(" minions have spawned! ")
                    local max=2+math.random(1)+math.ceil(GetPlayer().mylevel()/4)
                    local prd=15
                    if TUNING.RIVEN_ENOMOUS_MONSTER==2 then
                        max=4+math.random(2)+math.ceil(GetPlayer().mylevel()/2)
                        prd=6
                    end
                    local calcn=math.ceil(inst.GetPassedHalfDay()/prd)
                    if TUNING.RIVEN_ENOMOUS_MONSTER==2 then
                        calcn = calcn+1+math.random(1)
                    end  
                    if calcn<max then
                        max=calcn
                    end

                    if TUNING.RIVEN_ENOMOUS_MONSTER==2 then
                        local x,y,z=inst.Transform:GetWorldPosition()
                        local ents = TheSim:FindEntities(x,y,z, 30, {TUNING.RIVENBELONG})
                        if ents then
                            max=max+#ents*2
                        end
                    end   
                    for i = 1, max do 
                        local x, y, z = 0, 0, 0
                        local x0, y0, z0 = inst.Transform:GetWorldPosition()
                        for i = 1, 10 do
                            local rad = math.random(35, 100)
                            local angle = math.random() * 2 * PI
                            x, y, z = x0 + rad * math.cos(angle), y0, z0 + rad * math.sin(angle)
                            if testpoint(x,y,z) then
                                local theboss = shitswap("rivenmemberd")
                                theboss.Transform:SetPosition(x, y, z)
                                theboss.components.combat:SetTarget(inst)
                                break
                            end
                        end
                    end
                   inst.switchtoboss1 = false
                end 
            end
        end
        inst:DoPeriodicTask(15,inst.kyd)
    end
    
    inst.dif=1
    if TUNING.RIVEN_ENOMOUS_MONSTER==2 then
        inst.dif=0
    end
    inst.setbaseattr=setbaseattr
    inst.expvaluenum=0
    inst.levelvaluenum=1
    inst.q   = false
    inst.w   = false
    inst.e   = false
    inst.r   = false
    inst.canq = true
    inst.canw = true
    inst.cane = true
    inst.canr = true
    inst.qconbine = 0
    inst:DoTaskInTime(0, function() 
        SetHUDState(inst) 
        baseexp=baseexpclone
        for i=1,inst.mylevel()-1 do
            baseexp=math.ceil(baseexp*raise)
        end
        calculateAttribute(inst)
    end)
    inst.soundsname = "wendy"
    inst.MiniMapEntity:SetIcon( "riven.tex" )
    inst.removealltag=removealltag
    inst.nocasting=nocasting
    inst.destoryq=destoryq
    inst.qtimeout=qtimeout
    inst.qskilleffect = function()
        local player = GetPlayer()
        local walkspeed = player.components.locomotor.walkspeed
        local runspeed = player.components.locomotor.runspeed
        local weapon  = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) 
        if weapon and player.prefab=='riven' and not IsPaused() and not TheInput:IsKeyDown(KEY_CTRL) and not TheInput:IsKeyDown(KEY_SHIFT) 
            and nocasting(player)
            and not weapon:HasTag("rivenbowtype")  and not weapon:HasTag("notweapon")
            then
                if inst.canq then
                    removealltag(inst)
                    inst:AddTag("qbuffon")
                    inst.qtimeout(inst)
                end
        elseif not weapon then
            GetPlayer().components.talker:Say(" I need weapon ! ",nil,true) 
        end
    end
    inst.wskilleffect = function()
        local player = GetPlayer()
        local weapon  = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) 
        if weapon and not weapon:HasTag("rivenbowtype")  and not weapon:HasTag("notweapon") and player.prefab=='riven' and not IsPaused() and not TheInput:IsKeyDown(KEY_CTRL) and not TheInput:IsKeyDown(KEY_SHIFT) 
            then
          if  inst.canw then
            inst.canw = false
            if not inst:HasTag("w") then
                inst:AddTag("w")
            end
            if not inst:HasTag("skillw") then
                inst:AddTag("skillw")
            end
            inst.components.talker:Say(" Dizziness! ",nil,true) 
            inst.components.locomotor:Stop()
            inst.components.talker:ShutUp()
            inst.sg:GoToState("attack")
            local x2, y2, z2 = inst.Transform:GetWorldPosition()
            local fx = shitswap("rivenw")
            fx.Transform:SetScale(.4, .4, .4)
            local ents = TheSim:FindEntities(x2, y2, z2, 6)
            inst:DoTaskInTime(.3, function() 
            inst.components.xxxmagic_riven:DoDelta(35)
            fx.Transform:SetPosition(inst:GetPosition():Get())
                    local backpack = player.components.inventory:GetEquippedItem(EQUIPSLOTS.BODY)
                    if backpack and backpack.components.container then
                    else
                        backpack = nil 
                    end
                     for k,v in pairs(ents) do
                         if (v and v.components.container and v.components.container.canbeopened) 
                             or (v and v.components.follower and v.components.follower.leader == inst) then
                         elseif v and v.components.combat and v.components.health and v.components.health:GetPercent() >= 0 and v ~= inst 
                            and not (v:HasTag("mypet") or v:HasTag(inst.belongtowhich) and (v.components.combat and v.components.combat.target~= inst))
                            and player.components.inventory and not player.components.inventory:GetItemSlot(v)
                            and player.components.inventory:GetActiveItem()~=v
                            and not (backpack and backpack.components.container:GetItemSlot(v))
                            then
                            if  weapon and weapon.components.weapon and player.components.combat then 
                                local wdamage = 10
                                if  weapon and weapon.components.weapon then
                                 wdamage = weapon.components.weapon.damage
                                end
                                if  weapon and weapon.components.weapon and weapon.components.weapon.attackrange and weapon.components.weapon.attackrange>3 then 
                                    wdamage = wdamage /3
                                end
                                v.components.combat:GetAttacked(player, wdamage*inst.charcritmulti*1)  
                                if v.sg and not v.components.health:IsDead() then
                                    
                                    v.components.combat:BlankOutAttacks(1.5)
                                    if v.brain then
                                        v.brain:Stop()
                                    end
                                    if v.components.combat then
                                        v.components.combat:SetTarget(nil)
                                    end
                                    if v.components.locomotor then
                                        v.components.locomotor:Stop()
                                    end
                                    if v.components.combat then
                                        v.components.combat:GetAttacked(player, 1)  
                                    end 
                                    if v.sg and v.sg.sg and v.sg.sg.states and v.sg.sg.states.hit and not v.components.health:IsDead() then
                                        v.sg:GoToState("hit")
                                        local fx2 = shitswap("rivendizzy")
                                        fx2.Transform:SetPosition(0, 1.5 ,0)
                                        fx2.Transform:SetScale(1.2, 1.2, 1.2)
                                        fx2.entity:SetParent(v.entity) 
                                    end
                                    v:DoTaskInTime(1.5, function() 
                                        if v.brain then
                                            v.brain:Start()
                                            if v and v.components.combat and not v:HasTag("mypet")  then
                                                v.components.combat:SetTarget(player)
                                            end
                                        end
                                    end)
                                end
                            end
                         end
                     end
            if inst:HasTag("skillw") then
                inst:RemoveTag("skillw")
            end
            end) 
            player:DoTaskInTime(.6, function() 
                fx.kill_fx(fx)
            end) 

            player:DoTaskInTime(WCD*inst.cdtime*inst.changecdtimes, function() 
                inst.canw = true 
                if inst:HasTag("w") then
                    inst:RemoveTag("w")
                end
                if inst:HasTag("skillw") then
                    inst:RemoveTag("skillw")
                end
            end) 
          end
        end
    end
    inst.eskilleffect = function()
        local player = GetPlayer()
        local weapon  = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) 

        if inst:HasTag("skillq") and not inst:HasTag("qbuffon") then
            inst:RemoveTag("skillq")
        end
        if inst:HasTag("skille") and not inst:HasTag("ebuffon") then
            inst:RemoveTag("skille")
        end

        if weapon and player.prefab=='riven' and not IsPaused() and not TheInput:IsKeyDown(KEY_CTRL) and not TheInput:IsKeyDown(KEY_SHIFT) 
            and nocasting(player)
            and not weapon:HasTag("rivenbowtype")  and not weapon:HasTag("notweapon")
            then
            if  inst.cane then
                removealltag(inst)
                inst:AddTag("ebuffon")
                inst.qtimeout(inst)
            end
        elseif not weapon then
            GetPlayer().components.talker:Say(" I need weapon ! ",nil,true) 
        end
    end
    inst.rskilleffect = function()
        local player = GetPlayer()
        local weapon  = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) 
        if inst:HasTag("skillq") and not inst:HasTag("qbuffon") then
            inst:RemoveTag("skillq")
        end
        if inst:HasTag("skille") and not inst:HasTag("ebuffon") then
            inst:RemoveTag("skille")
        end
        if weapon and player.prefab=='riven' and not IsPaused() and not TheInput:IsKeyDown(KEY_CTRL) and not TheInput:IsKeyDown(KEY_SHIFT) 
            and not weapon:HasTag("rivenbowtype")  and not weapon:HasTag("notweapon")
            then
          if  inst.canr then
            removealltag(inst)
            if not inst:HasTag("rpre") then
                inst:AddTag("rpre")
                inst.components.talker:Say(" ...... ",nil,true) 
                local fx2=shitswap("statue_transition")
                if not fx2.components.highlight then
                    fx2:AddComponent("highlight")
                end
                fx2.components.highlight:SetAddColour(Vector3(0,1,0))
                fx2.Transform:SetScale(2, 2, 2)
                fx2.Transform:SetPosition(inst:GetPosition():Get())
                local fx=shitswap("explode_small")
                if not fx.components.highlight then
                    fx:AddComponent("highlight")
                end
                fx.components.highlight:SetAddColour(Vector3(0,1,0))
                fx.Transform:SetScale(2, 2, 2)
                fx.Transform:SetPosition(inst:GetPosition():Get())
                player.components.xxxmagic_riven:DoDelta(100)
                if  weapon and weapon.prefab=='rivensword' and player.AnimState then
                    weapon.components.equippable.onequipfn(weapon,player)
                end
            else
                inst:AddTag("rbuffon")
            end
            player:DoTaskInTime(15, function()
                inst.canr = false 
                if not inst:HasTag("r") then
                    inst:AddTag("r")
                end
                if inst:HasTag("skillr") then
                    inst:RemoveTag("skillr")
                end
                if inst:HasTag("rbuffon") then
                    inst:RemoveTag("rbuffon")
                end
                if inst:HasTag("rpre") then
                    inst:RemoveTag("rpre")
                end
                local nw = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS) 
                if  weapon and weapon.prefab=='rivensword' and player.AnimState 
                    and nw and nw == weapon
                then
                    weapon.components.equippable.onequipfn(weapon,player)
                end
            end)
            player:DoTaskInTime(RCD*inst.cdtime, function() 
                inst.canr = true 
                if inst:HasTag("r") then
                    inst:RemoveTag("r")
                end
                if inst:HasTag("rpre") then
                    inst:RemoveTag("rpre")
                end
                if inst:HasTag("rbuffon") then
                    inst:RemoveTag("rbuffon")
                end
            end) 
          end
        elseif not weapon then
            GetPlayer().components.talker:Say(" I need weapon ! ",nil,true) 
        end     
    end
    inst.taskq = inst:DoPeriodicTask(1, function()
      if not inst:HasTag("q")  then
            if not inst.q then
            inst.HUD.q = inst.HUD.jinenglan_riven:AddChild(ImageButton("images/q_riven.xml", "q_riven.tex"))
            inst.HUD.q:SetPosition(60, 30, 0)
            inst.HUD.q:SetVAnchor(ANCHOR_BOTTOM)
            inst.HUD.q:SetHAnchor(ANCHOR_LEFT)
            inst.HUD.q:SetTooltip("U")
            inst.HUD.q:MoveToFront()
            inst.HUD.q:SetOnClick(inst.qskilleffect)
            GetPlayer():DoTaskInTime(.5, function() inst.q = true end) 
            end  
      else
          if inst.HUD.q then
            inst.HUD.q:Kill()
            inst.HUD.q = nil
            GetPlayer():DoTaskInTime(.5, function() inst.q = false end)
          end
      end        
    end) 
    inst.taskw = inst:DoPeriodicTask(1, function()
      if not inst:HasTag("w")  then
            if not inst.w then
            inst.HUD.w = inst.HUD.jinenglan_riven:AddChild(ImageButton("images/w_riven.xml", "w_riven.tex"))
            inst.HUD.w:SetPosition(97, 30, 0)
            inst.HUD.w:SetVAnchor(ANCHOR_BOTTOM)
            inst.HUD.w:SetHAnchor(ANCHOR_LEFT)
            inst.HUD.w:SetTooltip("U")
            inst.HUD.w:MoveToFront()
            inst.HUD.w:SetOnClick(inst.wskilleffect)
            GetPlayer():DoTaskInTime(.5, function() inst.w = true end) 
            end  
      else
          if inst.HUD.w then
            inst.HUD.w:Kill()
            inst.HUD.w = nil
            GetPlayer():DoTaskInTime(.5, function() inst.w = false end)
          end
      end        
    end) 
    inst.taske = inst:DoPeriodicTask(1, function()
      if not inst:HasTag("e")  then
            if not inst.e then
            inst.HUD.e = inst.HUD.jinenglan_riven:AddChild(ImageButton("images/e_riven.xml", "e_riven.tex"))
            inst.HUD.e:SetPosition(135, 30, 0)
            inst.HUD.e:SetVAnchor(ANCHOR_BOTTOM)
            inst.HUD.e:SetHAnchor(ANCHOR_LEFT)
            inst.HUD.e:SetTooltip("U")
            inst.HUD.e:MoveToFront()
            inst.HUD.e:SetOnClick(inst.eskilleffect)
            GetPlayer():DoTaskInTime(.5, function() inst.e = true end) 
            end  
      else
          if inst.HUD.e then
            inst.HUD.e:Kill()
            inst.HUD.e = nil
            GetPlayer():DoTaskInTime(.5, function() inst.e = false end)
          end
      end        
    end) 
    inst.taskr = inst:DoPeriodicTask(1, function()
      if not inst:HasTag("r")  then
            if not inst.r then
            inst.HUD.r = inst.HUD.jinenglan_riven:AddChild(ImageButton("images/r_riven.xml", "r_riven.tex"))
            inst.HUD.r:SetPosition(171, 30, 0)
            inst.HUD.r:SetVAnchor(ANCHOR_BOTTOM)
            inst.HUD.r:SetHAnchor(ANCHOR_LEFT)
            inst.HUD.r:SetTooltip("U")
            inst.HUD.r:MoveToFront()
            inst.HUD.r:SetOnClick(inst.rskilleffect)
            GetPlayer():DoTaskInTime(.5, function() inst.r = true end) 
            end  
      else
          if inst.HUD.r then
            inst.HUD.r:Kill()
            inst.HUD.r = nil
            GetPlayer():DoTaskInTime(.5, function() inst.r = false end)
          end
      end        
    end) 
    TheInput:AddKeyUpHandler(TUNING.RIVEN_KEY.KEY1,inst.qskilleffect)
    TheInput:AddKeyUpHandler(TUNING.RIVEN_KEY.KEY2,inst.wskilleffect)
    TheInput:AddKeyUpHandler(TUNING.RIVEN_KEY.KEY3,inst.eskilleffect)
    TheInput:AddKeyUpHandler(TUNING.RIVEN_KEY.KEY4,inst.rskilleffect)
    inst:AddComponent("xxxmagic_riven")
    inst.task = inst:DoPeriodicTask(2/10, function()
        if inst.HUD and not inst.HUD.controls.magicbadge then
            if inst.task then
                inst.task:Cancel()
                inst.task = nil
            end
            inst.HUD.controls.magicbadge = GetPlayer().HUD.controls.sidepanel:AddChild(MagicBadge(inst)) 
            inst.HUD.controls.magicbadge:SetPosition(-180,-105,0) 
            inst.HUD.controls.magicbadge.anim:GetAnimState():SetBuild("xxxmagic_riven")
            inst.HUD.controls.magicbadge:SetPercent(0) 
            inst.HUD.controls.magicbadge.inst:ListenForEvent("xxxmagic_rivendelta", 
                function(_, data)
                    inst.HUD.controls.magicbadge:SetPercent(inst.components.xxxmagic_riven:GetPercent(), inst.components.xxxmagic_riven.max) 
                    if data.newpercent > data.oldpercent then
                        inst.HUD.controls.magicbadge:PulseGreen()
                    elseif data.newpercent < data.oldpercent then
                        inst.HUD.controls.magicbadge:PulseRed() 
                    end
                end
            , inst)
            inst.components.xxxmagic_riven:DoDelta(0,"riven")
         end
    end) 
    inst.OnSave = onsave
    inst.OnPreLoad = onpreload
    inst:AddComponent("rivencast")
    local tmp=inst.components.playeractionpicker.DoGetMouseActions
    local new = function ( force_target )
        local action, second_action = tmp( force_target )
        local weapon  = inst.components.inventory:GetEquippedItem(EQUIPSLOTS.HANDS)
        local position=Vector3(TheInput:GetWorldPosition():Get())
        local isCursorWet = false
        local passable = true
        local ground = inst.components.playeractionpicker.ground
        if not ground then
            ground = GetWorld()
        end
        if position and ground and ground.Map then
            local tile = ground.Map:GetTileAtPoint(position.x, position.y, position.z)
            passable = tile ~= GROUND.IMPASSABLE
        end
        isCursorWet= not passable
        if not isCursorWet and inst.GetIsOnWater then
            isCursorWet=inst:GetIsOnWater(position.x, position.y, position.z)
        end
        local shiping = inst.components.driver and inst.components.driver.vehicle
        if not inst.components.inventory:GetActiveItem() and weapon
            and not weapon:HasTag("rivenbowtype") and not weapon:HasTag("notweapon") 
            and (inst:HasTag("qbuffon") 
                or inst:HasTag("ebuffon") 
                or inst:HasTag("rbuffon"))
                and not second_action 
                and ((shiping and isCursorWet) or (not shiping and not isCursorWet))
                then
                       action =BufferedAction(inst, nil, ACTIONS.RIVENCAST)
                second_action =BufferedAction(inst, nil, ACTIONS.RIVENCASTCANCEL)
        end
        return action, second_action
    end
    inst.components.playeractionpicker.DoGetMouseActions=new
    inst:ListenForEvent("entity_death", function(wrld, data) onkill(inst, data) end, GetWorld())
    inst:ListenForEvent("onattackother", onattackother)
    inst:ListenForEvent("attacked", OnAttacked)
    if TUNING.RIVENREBORN~=1 then
        inst.components.resurrectable.FindClosestResurrector =  function ()
                    local item=shitswap("rivennil")
                    item:AddComponent("resurrector")
                    item.components.resurrector.active = true
                    item.components.resurrector.doresurrect = function ()
                        inst.deathtime = inst.deathtime+1
                        if inst.mylevel() >1 then
                            inst.levelvaluenum = inst.mylevel() -1
                        end
                        inst.expvaluenum = 0 
                        inst.money = 0
                        calculateAttribute(inst)
                        setattr(inst,true)
                        local rmp=getrandomposition()
                        inst.Transform:SetPosition(rmp.x, 0, rmp.z)
                        inst.sg:GoToState("amulet_rebirth")
                        item:Remove()
                    end
                    return item
        end
    end
    inst.laowang=false
    inst:ListenForEvent("daytime", function (global, data)
        if math.random()<inst.mylevel()*0.001*inst.probtimes then
            inst.laowang=true
        end
    end, GetWorld())
    inst:AddTag(inst.belongtowhich)
end
return MakePlayerCharacter("riven", prefabs, assets, fn, start_inv)