--зависимость продукта в процентах от сердечек
HeartsToProduct = { 30,30,60,60,90,110 };
VisualProductCount = { 1,1,2,2,3,3 };
-- не настраивать
-- получить рандомно время через которое должен сработать триггер, первый раз из first_timer={x,x,x} потом из timer={x,x,x}
function GetTriggerTimerRand(aTrigger)
    local aTimer = aTrigger.timer;
    if (aTrigger.was_called == nil) then
        aTrigger.was_called = 1;
        if (aTrigger.first_timer ~= nil) then
            aTimer = aTrigger.first_timer;
        end
    end
    local count = table.getn(aTimer);
    if(count==0)then return  end;
    local res  = Random(1, count);
    return aTimer[res];
end

function GetVisualProductCount(aHeartsCount)
    if (aHeartsCount < 1) then aHeartsCount = 1; end
    if (aHeartsCount > 6) then aHeartsCount = 6; end
    return VisualProductCount[aHeartsCount];
end

-- Тригер по умолчанию для всех желаний персонажа
function GetProductCreate()    
    aObject = GameObject:Get();
    local scores =  0;
    local aKoof = CPP_GetCurrentHeards();
    if (aKoof < 1) then 
        aKoof = 1; 
    else
        if (aKoof > 6) then 
            aKoof = 6;
        end
    end
    scores = aObject.Params.create_product * (HeartsToProduct[aKoof] / 100);
--ScriptDump("koef="..HeartsToProduct[aKoof]);
    
--[[    
    if aObject.Params.health  and  aObject.Params.MaxHealth then    
        aKoof = (aObject.Params.health / aObject.Params.MaxHealth);
    end
    ScriptDump("aKoof="..aKoof);

    if( aKoof > 0.75)then
        scores = aObject.Params.create_product;
    else
        if( aKoof >0.5)then
            scores = aObject.Params.create_product/4*3;
        else   
            if(aKoof > 0.25)then
                scores = aObject.Params.create_product/2;    
            else
                scores = aObject.Params.create_product/4;
            end
        end
    end
--]]
    return scores;
end    

-- Тригер по умолчанию для всех желаний персонажа
function defWishTriger(aTrigger, aWish, aParam)

    if ((not aTrigger.cur_value) or (aTrigger.cur_value == 0)) then
        aTrigger.cur_value = GetTriggerTimerRand(aTrigger);
        return;
    end
    
    aTrigger.cur_value = aTrigger.cur_value - 1;
    if (aTrigger.cur_value <= 0) then
        local res = CPP_OnTrigger(aWish,aParam); --имя задачи которую хотим без ид обьекта который обслужит
        if (res == 0) then
            aTrigger.cur_value = 1;
        else 
            if (res == -1) then
                aTrigger.cur_value = 10;
            else
                aTrigger.cur_value = 0;
            end
        end
    end
end



function SleepAfterTask(aTask)
    if( not aTask.sleeping)then return end;
    local count = table.getn(aTask.sleeping);
    if(count==0)then return  end;
    local res  = Random(1, count);
    --local s="";
    --s="count"..count.."         "..res.." - "..aTask.sleeping[res];
    --ScriptDump(s);  
    if( 0 ~= aTask.sleeping[res] and aTask.sleeping[res]~=nil) then 
        if (aTask.final_cycle == 1) then
            CPP_Sleep(1000,1);   --CPP_Sleep(aTask.sleeping[res],1);
        else
            CPP_Sleep(aTask.sleeping[res],0);
        end
    end;
end



-- выполнить Task EATING над внешним обьектом и вернуть true если выполнилась
function defEatingTaskExecute(aObjectParams,aTask)
    local effect = -250;
    if (aObjectParams.hungry == nil) then 
-- не было у обьекта поля hungry добавим в обьект, иначе надо сделать return
        aObjectParams.hungry = 0;
    end
    if (aObjectParams.hungry <= 250) then return 0; end
    aObjectParams.hungry = aObjectParams.hungry + effect;
    CPP_CheckAndSetVState("active_zone","eating",1);
    return 1;
end
-- выполнить Task DRINKING над внешним обьектом и вернуть true если выполнилась
function defWateringTaskExecute(aObjectParams,aTask)
    local effect = -250;
    if (aObjectParams.thirst == nil) then 
-- не было у обьекта поля hungry добавим в обьект, иначе надо сделать return
        aObjectParams.thirst = 0;
    end
    if (aObjectParams.thirst < 250) then return 0; end
    aObjectParams.thirst = aObjectParams.thirst + effect;
    CPP_CheckAndSetVState("active_zone","watering",1);
    return 1;
end


function ReliefWCExecute()
    aObject = GameObject:Get();
    local tTask = aObject.Params.timerTask;
    if (tTask < 0) then 
        --tTask = aObject.Tasks.relief_wc.timer; 
        tTask = GetRandomValue( aObject.Tasks.relief_wc.timer);
        CPP_SetAnimState("wc_disappear_up_stand");
    end
    if (tTask == 1) then
        CPP_SetAnimState("wc_appear_left_stand"); --left_stand");
    end
    tTask = tTask - 1;
    aObject.Params.timerTask = tTask;
    if (tTask < 0) then
        aObject.Params.timerTask = -1;
        CPP_SetAnimState("selected");
        CPP_SetAnimState("left_stand");
        OnEndTask("relief_wc",aObject.Tasks.relief_wc);                     
        return 0;
    end
    return 1;
end

function ReliefWCTriger()
    aObj = GameObject:Get();
    return defWishTriger(aObj.Triggers.ReliefWC, "relief", 1);
end

function CanTrashing(aActionName)
    if (aActionName == "eating") then return "trash"; end
    if (aActionName == "watering") then return "trash"; end
    if (aActionName == "tools") then return "trash"; end
    if (aActionName == "plank") then return "trash"; end
    return "";
end

-- получить новую ожидаемую задачу из массива life_cycle
function OnSetNextTask()
    aObj = GameObject:Get();   
    if (aObj.Cycle.max_index == 0) then
        aObj.Cycle.max_index = table.getn(life_cycle);
        --ScriptDump(""..aObj.Cycle.max_index);
    end
    aObj.Cycle.index = aObj.Cycle.index + 1;
    if (aObj.Cycle.index < 1 or aObj.Cycle.index > aObj.Cycle.max_index) then
        aObj.Cycle.index = 1;
    end
    local cycle = life_cycle[aObj.Cycle.index];
    return cycle[1];
    --ScriptDump(""..cycle[2]);
end
-- для засыпания после задачи цикла ТОЛЬКО тем у кого RandomTasks=3 для остальных SleepAfterTask(х)
function SleepAfterTaskCycle()
    aObj = GameObject:Get();   
    aObj.Cycle.index_sleep = aObj.Cycle.index_sleep + 1;
    if (aObj.Cycle.index_sleep < 1 or aObj.Cycle.index_sleep > aObj.Cycle.max_index) then 
        aObj.Cycle.index_sleep = 1; 
    end
    --ScriptDump("SleepAfterTaskCycle:"..aObj.Cycle.index);
    local cycle = life_cycle[aObj.Cycle.index_sleep];
    if (cycle[2] > 0) then
        if (aObj.Tasks[cycle[1]].final_cycle == 1) then
            CPP_Sleep(cycle[2],1);
        else
            CPP_Sleep(cycle[2],0);
        end;
    else
        if (aObj.Tasks[cycle[1]].final_cycle == 1) then
            CPP_Sleep(0,1);
        else
            CPP_Sleep(0,0);
        end
    end;
end

--триггер злости
function AngerTriger()
    aObj = GameObject:Get();
    aObj.Params.health = aObj.Params.health - aObj.Params.Impatience;
    CPP_OnHealthChanged(aObj.Params.health);    
    if(aObj.Params.health<0)then aObj.Params.health = 0; end;   
end

function OnWeary()
    aObj = GameObject:Get();
    aObj.Params.speed = aObj.Params.speed / 2;
    CPP_AddExpectedTasks("relax_kreslo");
end

function SetDeltaImpatience(aDelta)
    aObj = GameObject:Get();
    --if (GameObject.Params.ID == "cow") then
    --    ScriptDump("COW Impatience!");    
    --end
    aObj.Params.Impatience = aObj.Params.Impatience + aDelta;
    --если есть MaxImpatience у обьекта
    if (aObj.Params.MaxImpatience ~= nil) then
        if (aObj.Params.Impatience > aObj.Params.MaxImpatience) then 
            aObj.Params.Impatience = aObj.Params.MaxImpatience;
        end
    end
end

function DEBUG_PAUSE()
    ScriptDump("ID="..GameObject.Params.ID);
    local sizeLifeCycle = table.getn(life_cycle);
    local life_cycle_i;
    for i = 1, sizeLifeCycle, 1 do
        life_cycle_i = life_cycle[i];
        ScriptDump("task="..life_cycle_i[1].." pause"..life_cycle_i[2]);
    end
end

function SetDeltaPause(aDelta)
    local sizeLifeCycle = table.getn(life_cycle);
    local pause_cycle = 0;
    local life_cycle_i;
    --DEBUG_PAUSE();
    for i = 1, sizeLifeCycle, 1 do
        life_cycle_i = life_cycle[i];
        pause_cycle = life_cycle_i[2];
        if (pause_cycle > 0) then
            pause_cycle = pause_cycle + aDelta;
            if (pause_cycle < 0) then
                pause_cycle = 0;
            end
            life_cycle_i[2] = pause_cycle;
        end
    end
    --DEBUG_PAUSE();
end
-- реакция на потерю сердечка
-- aCurHearts - сколько счас стало сердечек, -1 если 0 и меньше
function OnAngerScore(aCurHearts)
    if (GameObject.Params.koef_anger == nil) then GameObject.Params.koef_anger = 0; end
    if (aCurHearts <= 0) then 
        GameObject.Params.koef_anger = GameObject.Params.koef_anger + 1;
    else
        GameObject.Params.koef_anger = 0;
    end
    local res = GameObject.Params.koef_anger;
    return res;
end





function DefPlankingTaskExecute(child, runstr)
    aObject = GameObject:Get();
    local aTrigger = aObject.Triggers.need_repair;
    aTrigger.under_task = 0;
    aTrigger.amount = aTrigger.amount - 1;
    CPP_SetAnimState("normal");
    if (aObject.idListener ~= nil and aObject.idListener > 0) then
        CPP_RunStringSubId(aObject.idListener,"DecRef();");
    end
    --починили забор
    if( runstr == "")then
        runstr = "GameObject.Params.Impatience=GameObject.Params.Impatience / " ..aTrigger.koef..";";
    end
    CPP_WantSelect(0);
    CPP_RunStringChild(child,runstr);
    return 0;
end


function DefNeedRepairTriger(child, runstr)
    aObject = GameObject:Get();
    local aTrigger = aObject.Triggers.need_repair;
    if (aTrigger.under_task == 1) then return; end
    if (aTrigger.amount <= 0) then return; end
    if ((not aTrigger.cur_value) or (aTrigger.cur_value == 0)) then
        aTrigger.cur_value = GetTriggerTimerRand(aTrigger);
        return;
    end
    aTrigger.cur_value = aTrigger.cur_value - 1;
    if (aTrigger.cur_value <= 0) then
        aTrigger.cur_value = 0;
        -- когда доступен триггер не должен работать
        aTrigger.under_task = 1;
        CPP_AddExpectedTasks("plank");
        if (aObject.idListener == nil) then
            aObject.idListener = CPP_FindObj("chopping");
        end
        if (aObject.idListener > 0) then
            CPP_RunStringSubId(aObject.idListener,"IncRef();");
        end
        --развалили забор
        if( runstr == "")then
            runstr = "GameObject.Params.Impatience=GameObject.Params.Impatience * " ..aTrigger.koef..";";
        end
        
        CPP_AddInQueue("dad",aObject.Params.SubId);
        CPP_RunStringChild(child,runstr);
        CPP_SetAnimState("breakege");
        CPP_PlaySound("breaking",0);
        CPP_WantSelect(1);
        --CPP_RecursiveRun("freezing_personage",0); --персонажи замерзли
    end
end

-- вся инициализация должа проходить только в этой функции
function OnInitHealth()
    aObj = GameObject:Get();   
    if( not aObj.Params.MaxHealth )then
        aObj.Params.MaxHealth = aObj.Params.health;
    end;
    if (aObj.Params.start_with_hearts ~= nil) then
        aObj.Params.health = (aObj.Params.start_with_hearts - 1) * aObj.Params.MaxHealth / 5; --где 5 = MAX_HEARTS_COUNT - 1
        CPP_SetAnimState("left_stand_hearts_"..aObj.Params.start_with_hearts);
    else
        CPP_SetAnimState("left_stand_hearts_6");
    end
end

function SleepOnEnd()
end


function SetDeltaInLifeCycle(aTask,aDelta)
    if (life_cycle == nil) then return; end
    local sizeObjTables = table.getn(life_cycle);
    local stepCycle;
    for icycle=1,sizeObjTables,1 do
        stepCycle = life_cycle[icycle];
        if (stepCycle[1] == aTask) then
            stepCycle[2] = stepCycle[2] + aDelta;
        end
    end
end


-- порча продуктов
-- старт когда продукт можно начать забирать
function OnStartSpoilPruduct()
    aObj = GameObject:Get();
    if (aObj.Params.spoil_end_time == nil or aObj.Params.spoil_end_time <= 0) then return; end
    if (aObj.Triggers.SpoilTrigger == nil) then return; end
    aObj.Triggers.SpoilTrigger.timer = aObj.Params.spoil_end_time;
    aObj.Triggers.SpoilTrigger.active = 1;
    aObj.Triggers.SpoilTrigger.end_timer = aObj.Params.spoil_end_time;
    aObj.Triggers.SpoilTrigger.warn_timer = aObj.Params.spoil_warning_time; 
end
--функция триггера
function SpoilTriggerExecute()
    aObj = GameObject:Get();
    if (aObj.Params.spoil_end_time == nil or aObj.Params.spoil_end_time <= 0) then return; end
    if (aObj.Triggers.SpoilTrigger.active == 0) then return; end
    aObj.Triggers.SpoilTrigger.timer = aObj.Triggers.SpoilTrigger.timer - 1;
    if (aObj.Triggers.SpoilTrigger.timer <= 0) then
        aObj.Triggers.SpoilTrigger.active = 0;
        aObj.Params.action_enabled = 0;
        --нету продукта у того кто его произвел уже
        CPP_RunStringParent("GameObject.Params.amount_product=0;");
        --исчезли
        TakeTaskExecute();
        return 0;
    end
    if (aObj.Triggers.SpoilTrigger.timer == aObj.Triggers.SpoilTrigger.warn_timer) then
        --портимся
        CPP_SetAnimState("spoiling_"..aObj.Params.vprod);
    end
end

-- функция заморозки триггера, если кликнули на продукт
function FreezeSpoil()
    aObj = GameObject:Get();
    if (aObj.Params.spoil_end_time == nil or aObj.Params.spoil_end_time <= 0) then return; end
    aObj.Triggers.SpoilTrigger.active = 0;
    CPP_SetAnimState(aObj.Params.vstate);
end

-- функция разморозки триггера, если убрали галку на продукте
function UnfreezeSpoil()
    aObj = GameObject:Get();
    if (aObj.Params.spoil_end_time == nil or aObj.Params.spoil_end_time <= 0) then return; end
    aObj.Triggers.SpoilTrigger.active = 1;
    if (aObj.Triggers.SpoilTrigger.timer <= aObj.Triggers.SpoilTrigger.warn_timer) then
        --портимся
        CPP_SetAnimState("spoiling_"..aObj.Params.vprod);
    else
        CPP_SetAnimState(aObj.Params.vstate);
    end
end

function TakeTaskExecute()
    aObj = GameObject:Get();   
    aObj.Triggers.SpoilTrigger.active = 0;
    CPP_SetAnimState("normal");
    CPP_SetVisible(0);
    CPP_SleepParent(1, 1);
    --ScriptDump("egg:TakeTaskExecute");
    return 0;
end

function DefNeedRepairTrigerFarm4(child, runstr)
    aObject = GameObject:Get();
    local aTrigger = aObject.Triggers.need_repair;
    if (aTrigger.under_task == 1) then return; end
    if (aTrigger.amount <= 0) then return; end
    if ((not aTrigger.cur_value) or (aTrigger.cur_value == 0)) then
        aTrigger.cur_value = GetTriggerTimerRand(aTrigger);
        return;
    end
    aTrigger.cur_value = aTrigger.cur_value - 1;
    if (aTrigger.cur_value <= 0) then
        aTrigger.cur_value = 0;
        -- когда доступен триггер не должен работать
        aTrigger.under_task = 1;
        CPP_AddExpectedTasks("br_plank");

        --развалили забор
        if( runstr == "")then
            runstr = "GameObject.Params.Impatience=GameObject.Params.Impatience * " ..aTrigger.koef..";";
        end
        
        CPP_RunStringChild(child,runstr);
        CPP_SetAnimState("breakege");
        CPP_PlaySound("breaking",0);
        CPP_WantSelect(1);
    end
end
