HWHNewCharacterExt

Extension for HeroWarsHelper script

// ==UserScript==
// @name             HWHNewCharacterExt
// @name:en          HWHNewCharacterExt
// @name:ru          HWHNewCharacterExt
// @namespace        HWHNewCharacterExt
// @version          1.52
// @description      Extension for HeroWarsHelper script
// @description:en   Extension for HeroWarsHelper script
// @description:ru   Расширение для скрипта HeroWarsHelper
// @author           ZingerY, Green
// @license          Copyright Green
// @match            https://www.hero-wars.com/*
// @match            https://apps-1701433570146040.apps.fbsbx.com/*
// @run-at           document-start
// ==/UserScript==

(function () {
    if (!this.HWHClasses) {
        console.log('%cObject for extension not found', 'color: red');
        return;
    }

    console.log('%cStart Extension ' + GM_info.script.name + ', v' + GM_info.script.version + ' by ' + GM_info.script.author, 'color: red');
    const { addExtentionName } = HWHFuncs;
    addExtentionName(GM_info.script.name, GM_info.script.version, GM_info.script.author);

    const { popup, confShow, setProgress, I18N, countdownTimer } = HWHFuncs;

    const { i18nLangData } = HWHData;

    const { WinFixBattle } = HWHClasses;

    const i18nLangDataEn = {
        NEWCHARACTER: 'New Character',
        NEWCHARACTER_TITLE: 'Complete quests for a new hero or titan',
        NEWCHARACTER_NOEVENT: 'The event is not active',
        NEWHERO: '<span style="color: green;"> New Hero Event </span> <br>',
        NEWTITAN: '<span style="color: green;"> New Titan Event </span> <br>',
        NEWHERO_COMPLETETASKS: 'Complete the tasks',
        NEWHERO_COMPLETETASKS_TITLE: 'Complete the event tasks',
        NEWHERO_COMPLETECAPTERS: 'Complete chapters',
        NEWHERO_COMPLETECAPTERS_TITLE: 'Complete chapters',
        NEWHERO_SELECTACTION: 'Select an action',
        NEWTITAN_GETTITANS: 'Сollect the Titans',
        NEWTITAN_GETTITANS_TITLE: 'Сollecting the Titans of the maximum rank by purchasing fragments in the store',
        NEWTITAN_GETHEROES: 'Сollect the Heroes',
        NEWTITAN_GETHEROES_TITLE: 'Сollecting the Heroes of the maximum rank by purchasing fragments in the store',
        NEWTITAN_GETINFLUENCESKILL: 'Сollect totem skills',
        NEWTITAN_GETINFLUENCESKILL_TITLE: 'Get the influence skill of the maximum rank by purchasing fragments in the store',
        NEWTITAN_GETTITANSPROGRESS: '<span style="color: green;"> {counter} </span> titans left to collect',
        NEWTITAN_GETTITANSCOLLECTED: 'All titans have been collected',
        NEWTITAN_GETINFLUENCESKILLCOLLECTED: 'All influence skills have been collected',
        NEWTITAN_GETINFLUENCESKILLPROGRESS: '<span style="color: green;"> {counter} </span> influence skills left to collect <br> Collecting...',
        NEWTITAN_CHAPTERNOTAVAILABLE: 'Chapter unavailable. Complete Chapter 1',
        NEWTITAN_GETHEROCOLLECTED: 'All heroes have been collected',
        NEWTITAN_GETHEROCOLLECTEDPROGRESS: '<span style="color: green;"> {counter} </span> heroes left to collect <br> Collecting...',
        NEWCHARACTER_SOMETHINGWENTWRONG: '<span style="color: red;"> Something went wrong </span> <br> Please try again',
        NEWTITAN_COLLECTEVERYTHING: 'Collect everything',
        NEWTITAN_COLLECTEVERYTHING_TITLE: 'Collect heroes, titans, totems, pets',
        NEWTITAN_BOSSWASKILLED: '<span style="color: green;"> The boss was killed </span>',
        NEWTITAN_BOSSWASNOTKILLED: '<span style="color: green;"> The boss was not killed </span> <br> Restart the game and kill the boss',
        NEWTITAN_COMPLETECHAPTER: 'Complete the chapter',
        NEWTITAN_COMPLETECHAPTER_TITLE: 'Complete an available chapter',
        NEWTITAN_COMPLETECHAPTERAllCOMPLETED: 'All chapters completed',
        NEWTITAN_NOTENOUGHBUFF: 'Not enough power to complete Chapter <span style="color: green;"> {chapterNumber} </span>'+
        'You have: <span style="color: red;"> {buffAmount} </span> <br>' +
        'You need: <span style="color: green;"> {invasionBuff} </span>',
        NEWTITAN_ENTERTITANIDS: 'Chapter <span style="color: green;"> {chapterNumber} </span> is available for completion <br> Enter <span style="color: red;"> 5 </span> titan IDs separated by commas or dashes',
        NEWTITAN_ENTERHEROIDS: 'Chapter <span style="color: green;"> {chapterNumber} </span> is available for completion <br> Enter <span style="color: red;"> 5 </span> hero IDs separated by commas or dashes',
        NEWTITAN_MUSTFIVETITANS:'There must be <span style="color: red;"> 5 </span> titans',
        NEWTITAN_MUSTFIVEHEROES:'There must be <span style="color: red;"> 5 </span> heroes',
        NEWTITAN_MUST_ONLY_NUMBERS: 'The list must contain only numbers and commas',
        NEWTITAN_LETSBEGIN: 'Let\'s start...',
        NEWTITAN_OUTDATEDVERSION: '<span style="color: red;"> Outdated version of HeroWarsHelper </span> <br> Please update the script',
        NEWTITAN_MISSION_PROGRESS: 'Attack <span style="color: green;"> {missionNumber} </span> enemy team',
    };

    i18nLangData['en'] = Object.assign(i18nLangData['en'], i18nLangDataEn);

    const i18nLangDataRu = {
        NEWCHARACTER: 'Новый персонаж',
        NEWCHARACTER_TITLE: 'Выполнять задания для нового героя или титана',
        NEWCHARACTER_NOEVENT: 'Ивент не активен',
        NEWHERO: '<span style="color: green;"> Событие Нового Героя </span> <br>',
        NEWTITAN: '<span style="color: green;"> Событие Нового Титана </span> <br>',
        NEWHERO_COMPLETETASKS: 'Выполнить задания',
        NEWHERO_COMPLETETASKS_TITLE: 'Выполнить заданий ивента',
        NEWHERO_COMPLETECAPTERS: 'Проходить главы',
        NEWHERO_COMPLETECAPTERS_TITLE: 'Проходить главы',
        NEWHERO_SELECTACTION: 'Выберите действие',
        NEWTITAN_GETTITANS: 'Собрать титанов',
        NEWTITAN_GETTITANS_TITLE: 'Собрать титанов максимального ранга, покупая фрагменты в магазине',
        NEWTITAN_GETHEROES: 'Собрать героев',
        NEWTITAN_GETHEROES_TITLE: 'Собрать героев максимального ранга, покупая фрагменты в магазине',
        NEWTITAN_GETINFLUENCESKILL: 'Собрать тотемы',
        NEWTITAN_GETINFLUENCESKILL_TITLE: 'Собрать навыки тотемов максимального ранга, покупая фрагменты в магазине',
        NEWTITAN_GETTITANSPROGRESS: 'Осталось собрать титанов: <span style="color: green;"> {counter} </span> шт.',
        NEWTITAN_GETTITANSCOLLECTED: 'Все титаны собраны',
        NEWTITAN_GETINFLUENCESKILLCOLLECTED: 'Все навыки влияния собраны',
        NEWTITAN_GETINFLUENCESKILLPROGRESS: 'Осталось собрать навыков тотемов: <span style="color: green;"> {counter} </span> шт. <br> Собираем...',
        NEWTITAN_CHAPTERNOTAVAILABLE: 'Глава не доступна. Завершите первую главу',
        NEWTITAN_GETHEROCOLLECTED: 'Все герои собраны',
        NEWTITAN_GETHEROCOLLECTEDPROGRESS: 'Осталось собрать героев: <span style="color: green;"> {counter} </span> шт. <br> Собираем...',
        NEWCHARACTER_SOMETHINGWENTWRONG: '<span style="color: red;"> Что-то пошло не так </span> <br> Попробуйте заново',
        NEWTITAN_COLLECTEVERYTHING: 'Собрать все',
        NEWTITAN_COLLECTEVERYTHING_TITLE: 'Собрать героев, титанов, тотемы, питомцев',
        NEWTITAN_BOSSWASKILLED: '<span style="color: green;"> Убили босса </span>',
        NEWTITAN_BOSSWASNOTKILLED: '<span style="color: green;"> Босса не убили </span> <br> Перезагрузите игру, и убейте босса',
        NEWTITAN_COMPLETECHAPTER: 'Пройти главу',
        NEWTITAN_COMPLETECHAPTER_TITLE: 'Пройти доступную главу',
        NEWTITAN_COMPLETECHAPTERAllCOMPLETED: 'Все главы пройдены',
        NEWTITAN_NOTENOUGHBUFF: 'Недостаточно усиления для прохождения <span style="color: green;"> {chapterNumber} </span> главы <br> ' +
        'У вас: <span style="color: red;"> {buffAmount} </span> <br>' +
        'Необходимо: <span style="color: green;"> {invasionBuff} </span>',
        NEWTITAN_ENTERTITANIDS: 'Для прохождения доступна <span style="color: green;"> {chapterNumber} </span> глава <br> Введите <span style="color: red;"> 5 </span> id <span style="color: green;"> титанов </span> через запятые или дефисы',
        NEWTITAN_ENTERHEROIDS: 'Для прохождения доступна <span style="color: green;"> {chapterNumber} </span> глава <br> Введите <span style="color: red;"> 5 </span> id <span style="color: green;"> героев </span> через запятые или дефисы',
        NEWTITAN_MUSTFIVETITANS:'Должно быть <span style="color: red;"> 5 </span> титанов',
        NEWTITAN_MUSTFIVEHEROES:'Должно быть <span style="color: red;"> 5 </span> героев',
        NEWTITAN_MUST_ONLY_NUMBERS: 'Список должен содержать только цифры и запятые',
        NEWTITAN_LETSBEGIN: 'Начинаем начинать...',
        NEWTITAN_OUTDATEDVERSION: '<span style="color: red;"> Устаревшая версия HeroWarsHelper </span> <br> Пожалуйста, обновите скрипт',
        NEWTITAN_MISSION_PROGRESS: 'Атакуем <span style="color: green;"> {missionNumber} </span> комнаду противника',
    };

    i18nLangData['ru'] = Object.assign(i18nLangData['ru'], i18nLangDataRu);

    ///////////////////////////////////////////////////////////////////////////////////////////////

    // Добавление кнопоки в окно Разное
    const { othersPopupButtons } = HWHData;
    othersPopupButtons.push({
        get msg() {
            return I18N('NEWCHARACTER');
        },
        get title() {
            return I18N('NEWCHARACTER_TITLE');
        },
        result: async function () {
            if (scriptInfo.version < 2.390){
                confShow(`${I18N('NEWTITAN_OUTDATEDVERSION')}`);
                return;
            }
            console.log(scriptInfo.version);
            let invasionInfo = await Caller.send('invasion_getInfo');
            let invasionInfoId = invasionInfo.id;

            if (invasionInfo) {
                let chapters = Object.values(lib.data.invasion.chapter).filter((e) => e.invasionId === invasionInfoId);
                let titanShopId = await getShopId(chapters, 'titan');
                try {
                    if (titanShopId) {
                        await onClickNewTitanButton();
                    } else {
                        await onClickNewHeroButton();
                    }
                } catch (e) {
                    confShow(`${I18N('NEWCHARACTER_SOMETHINGWENTWRONG')}`);
                }
            } else {
                confShow(`${I18N('NEWCHARACTER_NOEVENT')}`);
            }
        },
        color: 'pink',
    });

    async function onClickNewHeroButton() {
        const popupButtons = [
            {
                get msg() {
                    return I18N('NEWHERO_COMPLETETASKS');
                },
                get title() {
                    return I18N('NEWHERO_COMPLETETASKS_TITLE');
                },
                result: async function () {
                    confShow('Нажата кнопка');
                },
            },
            {
                get msg() {
                    return I18N('NEWHERO_COMPLETECAPTERS');
                },
                get title() {
                    return I18N('NEWHERO_COMPLETECAPTERS_TITLE');
                },
                result: () => {
                    confShow('Нажата кнопка 2');
                },
            },
        ];
        popupButtons.push({ result: false, isClose: true });
        const answer = await popup.confirm(`${I18N('NEWHERO')} ${I18N('NEWHERO_SELECTACTION')}`, popupButtons);
        if (typeof answer === 'function') {
            answer();
        }
    }

    async function onClickNewTitanButton() {
        const popupButtons = [
            {
                get msg() {
                    return I18N('NEWTITAN_GETTITANS');
                },
                get title() {
                    return I18N('NEWTITAN_GETTITANS_TITLE');
                },
                result: async function () {
                    await newTitanGetTitans();
                },
                color: 'green',
            },
            {
                get msg() {
                    return I18N('NEWTITAN_GETINFLUENCESKILL');
                },
                get title() {
                    return I18N('NEWTITAN_GETINFLUENCESKILL_TITLE');
                },
                result: async function () {
                    await newTitanGetInvasionFragmentSkill();
                },
                color: 'green',
            },
            {
                get msg() {
                    return I18N('NEWTITAN_GETHEROES');
                },
                get title() {
                    return I18N('NEWTITAN_GETHEROES_TITLE');
                },
                result: async function () {
                    let farmedChapters = await Caller.send('invasion_getInfo').then((e) => e.farmedChapters);
                    if (farmedChapters.length >= 1) {
                        await newTitanGetHeroes();
                    } else {
                        confShow(`${I18N('NEWTITAN_CHAPTERNOTAVAILABLE')}`);
                    }
                },
                color: 'green',
            },
            {
                get msg() {
                    return I18N('NEWTITAN_COLLECTEVERYTHING');
                },
                get title() {
                    return I18N('NEWTITAN_COLLECTEVERYTHING_TITLE');
                },
                result: async function () {
                    await newTitanGetTitans();
                    await newTitanGetInvasionFragmentSkill();
                    let farmedChapters = await Caller.send('invasion_getInfo').then((e) => e.farmedChapters);
                    if (farmedChapters.length >= 1) {
                        await newTitanGetHeroes();
                    } else {
                        confShow(`${I18N('NEWTITAN_CHAPTERNOTAVAILABLE')}`);
                    }
                },
                color: 'pink',
            },
            {
                get msg() {
                    return I18N('NEWTITAN_COMPLETECHAPTER');
                },
                get title() {
                    return I18N('NEWTITAN_COMPLETECHAPTER_TITLE');
                },
                result: async function () {
                    await newTitanCompleteChapter();
                },
                color: 'blue',
            },
        ];
        popupButtons.push({ result: false, isClose: true });
        const answer = await popup.confirm(`${I18N('NEWTITAN')} ${I18N('NEWHERO_SELECTACTION')}`, popupButtons);
        if (typeof answer === 'function') {
            answer();
        }
    }
    //****************************************************************************************************
    //****************************************************************************************************
    //****************************************************************************************************
    //****************************************************************************************************
    async function newTitanCompleteChapter() {
        //Получить состояние на карте
        let invasionInfo = await Caller.send('invasion_getInfo');
        let invasionInfoId = invasionInfo.id;
        let farmedChapters = invasionInfo.farmedChapters;
        let buffAmount = invasionInfo.buffAmount;
        console.log('invasionInfoId ' + invasionInfoId);
        console.log('farmedChapters ', JSON.stringify(farmedChapters));
        console.log('buffAmount ' + buffAmount);

        //Получить id главы для атаки
        let chapters = Object.values(lib.data.invasion.chapter).filter((e) => e.invasionId === invasionInfoId);
        if (chapters.length == farmedChapters.length) {
            confShow(I18N('NEWTITAN_GETTITANSCOLLECTED'));
        }
        console.log( chapters);
        let chapterId = 0;
        let invasionBuff = 0;
        let titanOrHero = '';
        let chapterNumber = 0;
        for (let chapter of chapters) {
            if (!farmedChapters.includes(chapter.id)) {
                chapterId = chapter.id;
                if (chapter.requirements?.invasionBuff) {
                    invasionBuff = chapter.requirements.invasionBuff;
                }
                titanOrHero = chapter.settings.unitType;
                chapterNumber = chapters.indexOf(chapter)+1;
                break;
            }
        }
        console.log('chapterId ' + chapterId);
        console.log('invasionBuff ' + invasionBuff);
        console.log('titanOrHero ' + titanOrHero);
        console.log('chapterNumber ' + chapterNumber);

        if (buffAmount < invasionBuff) {
            confShow(I18N('NEWTITAN_NOTENOUGHBUFF', { chapterNumber, buffAmount, invasionBuff}));
            return;
        }

        //Получить id магазина
        let shopId = getShopId(chapters, titanOrHero); //1073; // Магазин титанов
        console.log('Id магазина ' + shopId);
        if (titanOrHero === 'hero' ) {
            await сompleteHeroesChapter(shopId, chapterId, chapterNumber);
        }
        if (titanOrHero === 'titan' ) {
            await сompleteTitansChapter(shopId, chapterId, chapterNumber);
        }


    }
    async function сompleteHeroesChapter(shopId, chapterId, chapterNumber) {
        //Атакующие герои: Галахад, Тристан, Лирия, Кира, Себастьян.
        /*Питомцы
        6000 - Фенрис   //6005 - Альбрус
        6001 - Оливер	//6006 - Аксель
        6002 - Мерлин   //6007 - Бисквит
        6003 - Мара	    //6008 - Хорус
        6004 - Каин	    //6009 - Векс*/
        let heroAttackingTeams = {heroes: [2, 54, 67, 3, 48], pets: [6005,6000,6001,6006,6008]};
        let titanOrHero = 'hero';

        //Id героев, что необходимо собрать
        let heroIds = await getTeamButton(heroAttackingTeams.heroes, chapterNumber, titanOrHero);
        console.log('heroIds ', JSON.stringify(heroIds));
        if (!heroIds) {
            return;
        }
        setProgress(I18N('NEWTITAN_LETSBEGIN'), false);

        //Активировать главу
        let chapterInfo = await Caller.send({ name: 'invasion_setActiveChapter', args: { chapterId: chapterId } });
        let haveHeroFragments = chapterInfo.invasion.fragments;
        console.log('haveHeroFragments ', JSON.stringify(haveHeroFragments));

        //Id миссии
        let firstMissionId = chapterInfo.invasion.actions[0].payload.id;
        let missionId = firstMissionId;

        //Жизни
        let lives = chapterInfo.invasion.lives;
        console.log('firstMissionId ' + firstMissionId);
        console.log('missionId ' + missionId);
        console.log('lives ' + lives);

        //Фрагменты героев
        let heroFragments = [0, 0, 0, 0, 0];
        for (let i = 0; i < 5; i++) {
            if (haveHeroFragments[heroIds[i]]) {
                heroFragments[i] = haveHeroFragments[heroIds[i]];
            }
        }
        console.log('shopId ' + shopId);
        console.log(heroIds);
        console.log('heroFragments ', JSON.stringify(heroFragments));

        //Питомцы, что необходимо купить
        let pets = heroAttackingTeams.pets;

        while (lives > 0 && missionId <= firstMissionId + 7) {
            //Купить героев
            let result = await buyHeroesAndPets(shopId, heroIds, heroFragments, pets);

            //Текущая миссия босс или нет
            let boss = false;

            //Произвести атаку босса
            if (missionId == firstMissionId + 7) {
                boss = true;
                console.log('%cАтакуем босса ', 'color: green; font-weight: bold;');
            }

            //Получить атакующую команду
            let heroes = [];
            let havePets = [];
            let pet;
            await getAttackingTeam(heroes, havePets);
            console.log('heroes ', JSON.stringify(heroes));
            if (havePets.length > 0) {
                //Основной питомец 6005 - Альбрус
                let mainPet = 6005;
                if (havePets.includes(mainPet)) {
                    pet = mainPet;
                } else {
                    pet = havePets[0];
                }
            }

            //Проходим миссию
            setProgress(I18N('NEWTITAN_MISSION_PROGRESS', {missionNumber: 1 + missionId - firstMissionId}), false);
            await attackHeroMission(missionId, chapterId, heroes, pet, boss);

            //Результат атаки
            let invasionInfo = await Caller.send('invasion_getInfo');
            let missions = Object.values(invasionInfo.actions);
            for (let mission of missions) {
                if (mission.payload.wins == 0) {
                    missionId = mission.payload.id;
                    break;
                }
            }

            //Результат атаки босса
            if (boss) {
                if (invasionInfo.farmedChapters.includes(chapterId)) {
                    confShow(I18N('NEWTITAN_BOSSWASKILLED'));
                } else {
                    confShow(I18N('NEWTITAN_BOSSWASNOTKILLED'));
                }
                return;
            }
            lives = invasionInfo.lives;
            console.log('missionId ' + missionId);
            console.log('lives ' + lives);
        }
    }



    async function сompleteTitansChapter(shopId, chapterId, chapterNumber) {
        //Атакующие титаны: Ияри, Солярис, Молох, Игнис, Араджи
        /*Навыки тотемов:
        elemental                  primal
        4500 - Последний Всполох   4506 - Пульс Древних
        4502 - Ледниковый Период   4507 - Первородное Рвение
        4503 - Гнев Недр           4508 - Эгида Эха
        4509 - Танец Пламени       4514 - Тройной Круговорот
        4510 - Шепот Глубин        4515 - Зов Стихий
        4511 - Гул Скал */

        const elementalSkils = [4500,4502,4503,4509,4510,4511];
        const primalSkils = [4506,4507,4508,4514,4515]
        let titanAttackingTeams = {heroes: [4042, 4043, 4010, 4012, 4013], titanSkilsIds: [4500, 4507]};
        let titanOrHero = 'titan';

        //Id титанов, что необходимо собрать
        let titanIds = await getTeamButton(titanAttackingTeams.heroes, chapterNumber, titanOrHero);
        console.log('titanIds ', JSON.stringify(titanIds));
        if (!titanIds) {
            return;
        }
        setProgress(I18N('NEWTITAN_LETSBEGIN'), false);

        //Активировать главу
        let chapterInfo = await Caller.send({ name: 'invasion_setActiveChapter', args: { chapterId: chapterId } });
        let haveTitanFragments = chapterInfo.invasion.fragments;
        console.log('haveTitanFragments ', JSON.stringify(haveTitanFragments));

        //Id миссии
        let firstMissionId = chapterInfo.invasion.actions[0].payload.id;
        let missionId = firstMissionId;

        //Жизни
        let lives = chapterInfo.invasion.lives;
        console.log('firstMissionId ' + firstMissionId);
        console.log('missionId ' + missionId);
        console.log('lives ' + lives);

        //Фрагменты титанов
        let titanFragments = [0, 0, 0, 0, 0];
        for (let i = 0; i < 5; i++) {
            if (haveTitanFragments[titanIds[i]]) {
                titanFragments[i] = haveTitanFragments[titanIds[i]];
            }
        }
        console.log('shopId ' + shopId);
        console.log(titanIds);
        console.log('titanFragments ', JSON.stringify(titanFragments));

        //Навыки тотемов, что необходимо собрать
        let titanSkilsIds = titanAttackingTeams.titanSkilsIds;

        //Фрагменты навыков тотемов
        let titanSkilFragments = [];
        for (let t of titanSkilsIds){
            titanSkilFragments.push(0);
        }


        while (lives > 0 && missionId <= firstMissionId + 7) {
            //Купить титанов
            let result = await buyTitansAndTotemSkils(shopId, titanIds, titanFragments, titanSkilsIds, titanSkilFragments);

            //Текущая миссия босс или нет
            let boss = false;

            //Произвести атаку босса
            if (missionId == firstMissionId + 7) {
                boss = true;
                console.log('%cАтакуем босса ', 'color: green; font-weight: bold;');
            }

            //Получить атакующую команду
            let heroes = [];
            let titanSkil = [];
            await getAttackingTeam(heroes, titanSkil);
            console.log('heroes ', JSON.stringify(heroes));
            let spiritSkills = new Array();
            if (titanSkil.length > 0) {
                for (let ts of titanSkil) {
                    if (elementalSkils.includes(ts)) {
                        spiritSkills.push(['elemental', ts]);
                    }
                    if (primalSkils.includes(ts)) {
                        spiritSkills.push(['primalSkils', ts]);
                    }
                }
            }
            let firstSpiritSkills = Object.fromEntries(spiritSkills);

            //Проходим миссию
            setProgress(I18N('NEWTITAN_MISSION_PROGRESS', {missionNumber: 1 + missionId - firstMissionId}), false);
            await attackTitanMission(missionId, chapterId, heroes, firstSpiritSkills, boss);

            //Результат атаки
            let invasionInfo = await Caller.send('invasion_getInfo');
            let missions = Object.values(invasionInfo.actions);
            for (let mission of missions) {
                if (mission.payload.wins == 0) {
                    missionId = mission.payload.id;
                    break;
                }
            }

            //Результат атаки босса
            if (boss) {
                if (invasionInfo.farmedChapters.includes(chapterId)) {
                    confShow(I18N('NEWTITAN_BOSSWASKILLED'));
                } else {
                    confShow(I18N('NEWTITAN_BOSSWASNOTKILLED'));
                }
                return;
            }
            lives = invasionInfo.lives;
            console.log('missionId ' + missionId);
            console.log('lives ' + lives);
        }
    }

    async function newTitanGetTitans() {
        //Получить состояние на карте
        let invasionInfo = await Caller.send('invasion_getInfo');
        let invasionInfoId = invasionInfo.id;
        let farmedChapters = invasionInfo.farmedChapters;
        console.log('invasionInfoId ' + invasionInfoId);
        console.log('farmedChapters ', JSON.stringify(farmedChapters));

        //Получить id первой главый
        let chapters = Object.values(lib.data.invasion.chapter).filter((e) => e.invasionId === invasionInfoId);
        let chapterId = getChapterId(chapters, 'titan');
        console.log('chapterId ' + chapterId);

        //Получить id магазина
        let titanShopId = getShopId(chapters, 'titan'); //1073; // Магазин титанов
        console.log('Id магазина титанов ' + titanShopId);

        let cycle = true;
        while (cycle) {
            //Получить титанов, которых нужно собрать
            let allTitanIdsToBuy = await getTitanIdsToBuy();
            if (allTitanIdsToBuy.length == 0) {
                setProgress('', true);
                //await new Promise((e) => setTimeout(e, 4000));
                confShow(I18N('NEWTITAN_GETTITANSCOLLECTED'));
                cycle = false;
                return;
            }

            //Активировать главу
            let chapterInfo = await Caller.send({ name: 'invasion_setActiveChapter', args: { chapterId: chapterId } });
            let haveTitanFragments = chapterInfo.invasion.fragments;

            //Id миссии
            let firstMissionId = chapterInfo.invasion.actions[0].payload.id;
            let missionId = firstMissionId;

            //Жизни
            let lives = chapterInfo.invasion.lives;
            console.log('firstMissionId ' + firstMissionId);
            console.log('missionId ' + missionId);
            console.log('lives ' + lives);

            //Id титанов, что необходимо собрать
            let titanIds = [0, 0];
            if (allTitanIdsToBuy.length >= 2) {
                titanIds = [allTitanIdsToBuy[0], allTitanIdsToBuy[1]];
            } else {
                titanIds[0] = allTitanIdsToBuy[0];
                if (titanIds[0] != Number(Object.keys(haveTitanFragments)[0])) {
                    titanIds[1] = Number(Object.keys(haveTitanFragments)[0]);
                } else {
                    titanIds[1] = Number(Object.keys(haveTitanFragments)[1]);
                }
            }
            //Фрагменты титанов
            let titanFragments = [0, 0];
            if (haveTitanFragments[titanIds[0]]) {
                titanFragments[0] = haveTitanFragments[titanIds[0]];
            }
            if (haveTitanFragments[titanIds[1]]) {
                titanFragments[1] = haveTitanFragments[titanIds[1]];
            }

            console.log('titanShopId ' + titanShopId);
            console.log(titanIds);
            console.log(titanFragments);

            //Навыки тотемов, что необходимо собрать
            let titanSkilsIds = await getTitanSkillIdsToBuy();

            //Фрагменты навыков тотемов
            let titanSkilFragments = [0, 0];
            if (titanSkilsIds.length <= 1) {
                titanSkilFragments = [0];
            }

            setProgress(
                I18N('NEWTITAN_GETTITANSPROGRESS', { counter: allTitanIdsToBuy.length }) +
                    '<br>' +
                    I18N('NEWTITAN_GETINFLUENCESKILLPROGRESS', { counter: titanSkilsIds.length }),
                false
            );

            while (lives > 0 && missionId <= firstMissionId + 7) {
                //Купить титанов
                let result = await buyTitanInTheStore(titanShopId, titanIds, titanFragments, titanSkilsIds, titanSkilFragments);
                //Выйти, если босс побежден и полностью собрали двух титанов.
                if (result && farmedChapters.includes(chapterId)) {
                    break;
                }
                //Текущая миссия босс или нет
                let boss = false;

                //Произвести атаку босса, если его ни разу не убили
                if (!farmedChapters.includes(chapterId)) {
                    if (missionId == firstMissionId + 7) {
                        boss = true;
                        console.log('%cАтакуем босса ', 'color: green; font-weight: bold;');
                    }
                } else {
                    //Не атаковать босса, если его уже убили
                    if (missionId == firstMissionId + 7) {
                        break;
                    }
                }
                //Получить атакующую команду
                let heroes = [];
                let titanSkil = [];
                await getAttackingTeam(heroes, titanSkil);
                let firstSpiritSkills = {};

                //Проходим миссию
                setProgress(I18N('NEWTITAN_MISSION_PROGRESS', {missionNumber: 1 + missionId - firstMissionId}), false);
                await attackTitanMission(missionId, chapterId, heroes, firstSpiritSkills, boss);

                //Результат атаки
                let invasionInfo = await Caller.send('invasion_getInfo');
                farmedChapters = invasionInfo.farmedChapters;
                let missions = Object.values(invasionInfo.actions);
                for (let mission of missions) {
                    if (mission.payload.wins == 0) {
                        missionId = mission.payload.id;
                        break;
                    }
                }
                lives = invasionInfo.lives;
                console.log('missionId ' + missionId);
                console.log('lives ' + lives);
            }
        }
    }
    async function newTitanGetInvasionFragmentSkill() {
        //Получить состояние на карте
        let invasionInfo = await Caller.send('invasion_getInfo');
        let invasionInfoId = invasionInfo.id;
        let farmedChapters = invasionInfo.farmedChapters;
        console.log('invasionInfoId ' + invasionInfoId);
        console.log('farmedChapters ', JSON.stringify(farmedChapters));

        //Получить id первой главый
        let chapters = Object.values(lib.data.invasion.chapter).filter((e) => e.invasionId === invasionInfoId);
        let chapterId = getChapterId(chapters, 'titan');
        console.log('chapterId ' + chapterId);

        //Получить id магазина
        let titanShopId = getShopId(chapters, 'titan'); //1073; // Магазин титанов
        console.log('Id магазина титанов ' + titanShopId);

        let cycle = true;
        while (cycle) {
            //Получить навыки тотемов, которые нужно собрать
            let titanSkilsIds = await getTitanSkillIdsToBuy();
            if (titanSkilsIds.length == 0) {
                setProgress('', true);
                confShow(I18N('NEWTITAN_GETINFLUENCESKILLCOLLECTED'));
                cycle = false;
                return;
            }
            console.log(titanSkilsIds);
            setProgress(I18N('NEWTITAN_GETINFLUENCESKILLPROGRESS', { counter: titanSkilsIds.length }), false);

            //Фрагменты навыков тотемов
            let titanSkilFragments = [0, 0];
            if (titanSkilsIds.length == 1) {
                titanSkilFragments = [0];
            }

            //Активировать главу
            let chapterInfo = await Caller.send({ name: 'invasion_setActiveChapter', args: { chapterId: chapterId } });
            let haveTitanFragments = chapterInfo.invasion.fragments;

            //Id миссии
            let firstMissionId = chapterInfo.invasion.actions[0].payload.id;
            let missionId = firstMissionId;

            //Жизни
            let lives = chapterInfo.invasion.lives;
            console.log('firstMissionId ' + firstMissionId);
            console.log('missionId ' + missionId);
            console.log('lives ' + lives);

            //Id титанов, что необходимо купить
            //Ияри и Солярис
            let titanIds = [4042, 4043];

            //Фрагменты титанов
            let titanFragments = [0, 0];
            if (haveTitanFragments[titanIds[0]]) {
                titanFragments[0] = haveTitanFragments[titanIds[0]];
            }
            if (haveTitanFragments[titanIds[1]]) {
                titanFragments[1] = haveTitanFragments[titanIds[1]];
            }

            console.log('titanShopId ' + titanShopId);
            console.log(titanIds);
            console.log(titanFragments);

            while (lives > 0 && missionId <= firstMissionId + 7) {
                //Купить титанов и навыки тотемов
                let result = await buyTotemSkilsInTheStore(titanShopId, titanIds, titanFragments, titanSkilsIds, titanSkilFragments);
                //Выйти, если босс побежден и полностью собрали два навыка тотема
                if (result && farmedChapters.includes(chapterId)) {
                    break;
                }

                //Произвести атаку босса, если его ни разу не убили
                if (!farmedChapters.includes(chapterId)) {
                    if (missionId == firstMissionId + 7) {
                        console.log('%cАтакуем босса ', 'color: green; font-weight: bold;');
                    }
                } else {
                    //Не атаковать босса, если его уже убили
                    if (missionId == firstMissionId + 7) {
                        break;
                    }
                }

                //Получить атакующую команду
                let heroes = [];
                let titanSkil = [];
                await getAttackingTeam(heroes, titanSkil);
                console.log(heroes);

                let firstSpiritSkills = {};

                //Проходим миссию
                setProgress(I18N('NEWTITAN_MISSION_PROGRESS', {missionNumber: 1 + missionId - firstMissionId}), false);
                await attackTitanMission(missionId, chapterId, heroes, firstSpiritSkills);

                //Результат атаки
                let invasionInfo = await Caller.send('invasion_getInfo');
                farmedChapters = invasionInfo.farmedChapters;
                let missions = Object.values(invasionInfo.actions);
                for (let mission of missions) {
                    if (mission.payload.wins == 0) {
                        missionId = mission.payload.id;
                        break;
                    }
                }
                lives = invasionInfo.lives;
                console.log('missionId ' + missionId);
                console.log('lives ' + lives);
            }
        }
    }

    async function newTitanGetHeroes() {
        //Получить состояние на карте
        let invasionInfo = await Caller.send('invasion_getInfo');

        let invasionInfoId = invasionInfo.id;
        let farmedChapters = invasionInfo.farmedChapters;
        console.log('invasionInfoId ' + invasionInfoId);
        console.log('farmedChapters ', JSON.stringify(farmedChapters));

        //Получить id главый
        let chapters = Object.values(lib.data.invasion.chapter).filter((e) => e.invasionId === invasionInfoId);
        let chapterId = getChapterId(chapters, 'hero');
        console.log('chapterId ' + chapterId);

        //Получить id магазина
        let heroShopId = getShopId(chapters, 'hero'); //1074; // Магазин героев
        console.log('Id магазина героев ' + heroShopId);

        //Счетчик купленных питомцев
        let petCounter = [0];

        let cycle = true;
        while (cycle) {
            //Получить героев, которых нужно собрать
            let heroIdsToBuy = await getHeroIdsToBuy();
            if (heroIdsToBuy.length == 0) {
                setProgress('', true);
                confShow(I18N('NEWTITAN_GETHEROCOLLECTED'));
                cycle = false;
                return;
            }
            console.log(heroIdsToBuy);
            setProgress(I18N('NEWTITAN_GETHEROCOLLECTEDPROGRESS', { counter: heroIdsToBuy.length }), false);

            //Активировать главу
            let chapterInfo = await Caller.send({ name: 'invasion_setActiveChapter', args: { chapterId: chapterId } });
            let haveHeroFragments = chapterInfo.invasion.fragments;

            //Id миссии
            let firstMissionId = chapterInfo.invasion.actions[0].payload.id;
            let missionId = firstMissionId;

            //Жизни
            let lives = chapterInfo.invasion.lives;
            console.log('firstMissionId ' + firstMissionId);
            console.log('missionId ' + missionId);
            console.log('lives ' + lives);

            //Id героев, что необходимо купить
            let heroIds = [0, 0, 0];

            if (heroIdsToBuy.length >= 3) {
                heroIds = [heroIdsToBuy[0], heroIdsToBuy[1], heroIdsToBuy[2]];
            }
            //Резервные герои, для добавления в покупки: Галахад, Тристан, Лирия
            let reserveHeroes = [2, 54, 67];
            if (heroIdsToBuy.length == 2) {
                heroIds[0] = heroIdsToBuy[0];
                heroIds[1] = heroIdsToBuy[1];
                for (let r of reserveHeroes) {
                    if (r != heroIds[0] && r != heroIds[1]) {
                        heroIds[2] = r;
                        break;
                    }
                }
            }

            if (heroIdsToBuy.length == 1) {
                if (farmedChapters.includes(heroIds[0])) {
                    heroIds = reserveHeroes;
                } else {
                    heroIds[0] = heroIdsToBuy[0];
                    heroIds[1] = reserveHeroes[0];
                    heroIds[2] = reserveHeroes[1];
                }
            }

            //Фрагменты героев
            let heroFragments = [0, 0, 0];
            if (haveHeroFragments[heroIds[0]]) {
                heroFragments[0] = haveHeroFragments[heroIds[0]];
            }
            if (haveHeroFragments[heroIds[1]]) {
                heroFragments[1] = haveHeroFragments[heroIds[1]];
            }
            if (haveHeroFragments[heroIds[2]]) {
                heroFragments[2] = haveHeroFragments[heroIds[2]];
            }
            console.log(heroIds);
            console.log(heroFragments);

            while (lives > 0 && missionId <= firstMissionId + 7) {
                //Купить героев и питомцев
                let result = await buyHeroInTheStore(heroShopId, heroIds, heroFragments, petCounter);

                //Выйти, если босс побежден и полностью собрали три героя
                if (result && farmedChapters.includes(chapterId)) {
                    break;
                }

                //Текущая миссия босс или нет
                let boss = false;

                //Произвести атаку босса, если его ни разу не убили
                if (!farmedChapters.includes(chapterId)) {
                    if (missionId == firstMissionId + 7) {
                        boss = true;
                        console.log('%cАтакуем босса ', 'color: green; font-weight: bold;');
                    }
                } else {
                    //Не атаковать босса, если его уже убили
                    if (missionId == firstMissionId + 7) {
                        break;
                    }
                }
                //Получить атакующую команду
                let heroes = [];
                let havePets = [];
                let pet;
                await getAttackingTeam(heroes, havePets);
                console.log('heroes ', JSON.stringify(heroes));
                if (havePets.length > 0) {
                    //Основной питомец 6005 - Альбрус
                    let mainPet = 6005;
                    if (havePets.includes(mainPet)) {
                        pet = mainPet;
                    } else {
                        pet = havePets[0];
                    }
                }
                console.log('Атакующие герои ' + heroes);

                //Проходим миссию
                setProgress(I18N('NEWTITAN_MISSION_PROGRESS', {missionNumber: 1 + missionId - firstMissionId}), false);
                await attackHeroMission(missionId, chapterId, heroes, pet, boss);

                //Результат атаки
                let invasionInfo = await Caller.send('invasion_getInfo');
                farmedChapters = invasionInfo.farmedChapters;
                let missions = Object.values(invasionInfo.actions);
                for (let mission of missions) {
                    if (mission.payload.wins == 0) {
                        missionId = mission.payload.id;
                        break;
                    }
                }
                lives = invasionInfo.lives;
                console.log('missionId ' + missionId);
                console.log('lives ' + lives);
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    async function getHeroIdsToBuy() {
        const quest = await Caller.send('questGetAll');
        const heroIds = quest
            .filter((e) => e.state == 1 && lib.data.quest.special[e.id]?.translationMethod === 'invasionStallHeroFragments')
            .map((e) => lib.data.quest.special[e.id].farmCondition.eventFunc.args.fragmentId);
        return heroIds;
    }

    async function getTitanIdsToBuy() {
        const quest = await Caller.send('questGetAll');
        const titanIds = quest
            .filter((e) => e.state == 1 && lib.data.quest.special[e.id]?.translationMethod === 'invasionStallFragmentsTitans')
            .map((e) => lib.data.quest.special[e.id].farmCondition.eventFunc.args.fragmentId);
        return titanIds;
    }

    async function getTitanSkillIdsToBuy() {
        const quest = await Caller.send('questGetAll');
        const titanSkillIds = quest
            .filter((e) => e.state == 1 && lib.data.quest.special[e.id]?.translationMethod === 'invasionStallFragmentsTitanSkills')
            .map((e) => lib.data.quest.special[e.id].farmCondition.eventFunc.args.fragmentId);
        return titanSkillIds;
    }

    function getShopId(chapters, titanOrHero) {
        for (let chapter of chapters) {
            if (chapter.settings.unitType === titanOrHero) {
                return chapter.settings.stallShopId;
            }
        }
        return false;
    }
    function getChapterId(chapters, titanOrHero) {
        for (let chapter of chapters) {
            if (chapter.settings.unitType === titanOrHero) {
                return chapter.id;
            }
        }
        return false;
    }

    async function getAttackingTeam (heroes, other = []) {
        let haveFragments = Object.entries(await Caller.send('invasion_getInfo').then((e) => e.fragments)).map(e => ({id:e[0],count:e[1]})).sort((a, b) => b.count - a.count);
        console.log(haveFragments);
        for (let m of haveFragments) {
            //Отделяем питомцев и фрагменты тотемов
            if (Number(m.id) < 4400 && heroes.length < 5) {
                heroes.push(Number(m.id));
            }
            if (Number(m.id) > 4400) {
                other.push(Number(m.id));
            }
        }
    }

    async function getTeamButton (titanAttackingTeams, chapterNumber, titanOrHero) {
        let message = '';
        if (titanOrHero === 'titan' ) {
            message = I18N('NEWTITAN_ENTERTITANIDS', {chapterNumber:chapterNumber});
        }
        if (titanOrHero === 'hero' ) {
            message = I18N('NEWTITAN_ENTERHEROIDS', {chapterNumber:chapterNumber});
        }
        const answer = await popup.confirm(message, [
            {
                msg: I18N('NEWTITAN_COMPLETECHAPTER'),
                placeholder: '1,2,3,4,5,6',
                isInput: true,
                default: titanAttackingTeams,
                color: 'green',
            },
            {
                msg: I18N('BTN_CANCEL'),
                result: false,
                isCancel: true,
                color: 'red',
            },
        ]);
        if (!answer) {
            return false;
        }

        let team = answer.split(',');
        if (team.length != 5) {
            team = answer.split('-');
        }

        if (team.length != 5) {
            if (titanOrHero === 'hero' ) {
                confShow(I18N('NEWTITAN_MUSTFIVEHEROES'));
            }
            if (titanOrHero === 'titan' ) {
                confShow(I18N('NEWTITAN_MUSTFIVETITANS'));
            }
            return false;
        }

        for (let p in team) {
            team[p] = +team[p].trim()
            if (Number.isNaN(team[p])) {
                confShow(I18N('NEWTITAN_MUST_ONLY_NUMBERS'));
                return false;
            }
        }
        return team;
    }

    async function buyTitanInTheStore(titanShopId, titanIds, titanFragments, titanSkilsIds, titanSkilFragments) {
        console.log('Зашли в магазин');
        console.log('titanIds ', JSON.stringify(titanIds));
        console.log('titanFragments ', JSON.stringify(titanFragments));
        console.log('titanSkilsIds ', JSON.stringify(titanSkilsIds));
        console.log('titanSkilFragments ', JSON.stringify(titanSkilFragments));

        let coins = await Caller.send('inventoryGet').then((e) => e.coin[1080]);
        console.log('Монеты: ' + coins);

        let shopSlots = null;

        while (coins >= 9) {
            //Получить состояние магазина
            if (!shopSlots) {
                shopSlots = await Caller.send([{ name: 'shopGet', args: { shopId: titanShopId } }]).then((e) => Object.values(e.slots));
            }
            for (let slot of shopSlots) {
                //Пропустить скрытые лоты
                if (slot.reward.invasionFragmentTitanRand || slot.reward.invasionFragmentSkillRand) {
                    continue;
                }
                //Купить первого титана
                if (slot.reward.invasionFragmentTitan?.[titanIds[0]] && titanFragments[0] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплен титан ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanFragments[0] += slot.reward.invasionFragmentTitan?.[titanIds[0]];

                        //Если c первым титаном есть второй
                        if (slot.reward.invasionFragmentTitan?.[titanIds[1]]) {
                            console.log('%cВторой титан в комплекте ', 'color: green; font-weight: bold;');
                            titanFragments[1] += slot.reward.invasionFragmentTitan?.[titanIds[1]];
                        }
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }

                //Купить второго титана
                if (slot.reward.invasionFragmentTitan?.[titanIds[1]] && titanFragments[1] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплен титан ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanFragments[1] += slot.reward.invasionFragmentTitan?.[titanIds[1]];
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }

                //Купить первый навык тотема
                if (slot.reward.invasionFragmentSkill?.[titanSkilsIds[0]] && titanSkilFragments[0] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплена часть навыка тотема ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanSkilFragments[0] += slot.reward.invasionFragmentSkill?.[titanSkilsIds[0]];
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }

                //Купить второй навык тотема
                if (titanSkilsIds.length >= 2 && slot.reward.invasionFragmentSkill?.[titanSkilsIds[1]] && titanSkilFragments[1] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплена часть навыка тотема ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanSkilFragments[1] += slot.reward.invasionFragmentSkill?.[titanSkilsIds[1]];
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }
                //Если ТИТАНЫ собраны
                if (titanFragments[0] >= 7 && titanFragments[1] >= 7) {
                    //Обновляем навыки
                    if (titanSkilsIds.length >= 2 && titanSkilFragments[0] >= 7 && titanSkilFragments[1] >= 7) {
                        console.log('%cМеняем навыки навыки тотемов', 'color: green; font-weight: bold;');
                        titanSkilsIds = await getTitanSkillIdsToBuy();
                        titanSkilFragments = [0, 0];
                        if (titanSkilsIds.length == 1) {
                            titanSkilFragments = [0];
                        }
                    }
                    if ((titanSkilsIds.length == 1 && titanSkilFragments[0] >= 7) || titanSkilsIds.length == 0) {
                        console.log('%cВсе навыки тотемов куплены, переходим к покупке следующих титанов', 'color: green; font-weight: bold;');
                        return true;
                    }
                }
            }
            //Обновить магазин
            if (coins >= 12) {
                shopSlots = await Caller.send([{ name: 'shopRefresh', args: { shopId: titanShopId } }]).then((e) => Object.values(e.slots));
                coins -= 3;
                console.log('Обновили магазин. Осталось монет: ' + coins);
                if (shopSlots.error) {
                    coins = 0;
                }
            } else {
                break;
            }
        }
        return false;
    }

    async function buyTotemSkilsInTheStore(titanShopId, titanIds, titanFragments, titanSkilsIds, titanSkilFragments) {
        console.log('Зашли в магазин');
        console.log('titanIds ', JSON.stringify(titanIds));
        console.log('titanFragments ', JSON.stringify(titanFragments));
        console.log('titanSkilsIds ', JSON.stringify(titanSkilsIds));
        console.log('titanSkilFragments ', JSON.stringify(titanSkilFragments));

        let coins = await Caller.send('inventoryGet').then((e) => e.coin[1080]);
        console.log('Монеты: ' + coins);

        let shopSlots = null;
        while (coins >= 9) {
            //Получить состояние магазина
            if (!shopSlots) {
                shopSlots = await Caller.send([{ name: 'shopGet', args: { shopId: titanShopId } }]).then((e) => Object.values(e.slots));
            }
            for (let slot of shopSlots) {
                //Пропустить скрытые лоты
                if (slot.reward.invasionFragmentTitanRand || slot.reward.invasionFragmentSkillRand) {
                    continue;
                }
                //Купить первый навык тотема
                if (slot.reward.invasionFragmentSkill?.[titanSkilsIds[0]] && titanSkilFragments[0] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплена часть навыка тотема ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanSkilFragments[0] += slot.reward.invasionFragmentSkill?.[titanSkilsIds[0]];
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }

                //Купить второй навык тотема
                if (titanSkilsIds.length >= 2 && slot.reward.invasionFragmentSkill?.[titanSkilsIds[1]] && titanSkilFragments[1] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплена часть навыка тотема ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanSkilFragments[1] += slot.reward.invasionFragmentSkill?.[titanSkilsIds[1]];
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }
                //Если навыки собраны, обновляем навыки
                if (titanSkilsIds.length >= 2 && titanSkilFragments[0] >= 7 && titanSkilFragments[1] >= 7) {
                    titanSkilsIds = await getTitanSkillIdsToBuy();
                    titanSkilFragments = [0, 0];
                    if (titanSkilsIds.length == 1) {
                        titanSkilFragments = [0];
                    }
                }

                if ((titanSkilsIds.length == 1 && titanSkilFragments[0] >= 7) || titanSkilsIds.length == 0) {
                    //Тратим оставшиеся монеты (пусть будет, вдруг пригодиццо)
                    /*if (coins >= slot.cost.coin[1080]){
                        let shopBuy = await Caller.send({name: 'shopBuy', args: {cost: {}, reward: {}, shopId: titanShopId, slot: slot.id}});
                        coins -= slot.cost.coin[1080];
                        if(shopBuy.error){
                            coins = 0;
                            continue;
                        }
                    }*/
                    //Купили все навыки, идем на выход
                    return true;
                }

                //Купить первого титана
                if (slot.reward.invasionFragmentTitan?.[titanIds[0]] && titanFragments[0] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплен титан ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanFragments[0] += slot.reward.invasionFragmentTitan?.[titanIds[0]];

                        //Если c первым титаном есть второй
                        if (slot.reward.invasionFragmentTitan?.[titanIds[1]]) {
                            console.log('%cВторой титан в комплекте ', 'color: green; font-weight: bold;');
                            titanFragments[1] += slot.reward.invasionFragmentTitan?.[titanIds[1]];
                        }
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }

                //Купить второго титана
                if (slot.reward.invasionFragmentTitan?.[titanIds[1]] && titanFragments[1] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: titanShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплен титан ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        titanFragments[1] += slot.reward.invasionFragmentTitan?.[titanIds[1]];
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: titanShopId, slotId: slot.id } });
                    }
                    continue;
                }
            }
            //Обновить магазин
            if (coins >= 12) {
                shopSlots = await Caller.send({ name: 'shopRefresh', args: { shopId: titanShopId } }).then((e) => Object.values(e.slots));
                coins -= 3;
                console.log('Обновили магазин. Осталось монет ' + coins);
                if (shopSlots.error) {
                    coins = 0;
                }
            } else {
                break;
            }
        }
        return false;
    }

    async function buyHeroInTheStore(heroShopId, heroIds, heroFragments, petCounter) {
        console.log('Зашли в магазин');
        console.log('heroShopId ' + heroShopId);
        console.log('petCounter ' + petCounter[0]);
        console.log('heroIds ', JSON.stringify(heroIds));
        console.log('heroFragments ', JSON.stringify(heroFragments));

        let coins = await Caller.send('inventoryGet').then((e) => e.coin[1080]);
        console.log('Монеты: ' + coins);

        let shopSlots = null;

        while (coins >= 9) {
            //Получить состояние магазина
            if (!shopSlots) {
                shopSlots = await Caller.send([{ name: 'shopGet', args: { shopId: heroShopId } }]).then((e) => Object.values(e.slots));
            }
            for (let slot of shopSlots) {
                //Пропустить скрытые лоты
                if (slot.reward.invasionFragmentHeroRand) {
                    continue;
                }
                //console.log(slot);
                //Купить первого героя
                if (slot.reward.invasionFragmentHero?.[heroIds[0]] && heroFragments[0] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: heroShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: heroShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплен герой ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        heroFragments[0] += slot.reward.invasionFragmentHero?.[heroIds[0]];

                        //Если c первым титаном есть второй
                        if (slot.reward.invasionFragmentHero?.[heroIds[1]]) {
                            console.log('%cВторой герой в комплекте ', 'color: green; font-weight: bold;');
                            heroFragments[1] += slot.reward.invasionFragmentHero?.[heroIds[1]];
                        }
                        //Если c первым титаном есть третий
                        if (slot.reward.invasionFragmentHero?.[heroIds[2]]) {
                            console.log('%cТретий герой в комплекте ', 'color: green; font-weight: bold;');
                            heroFragments[2] += slot.reward.invasionFragmentHero?.[heroIds[2]];
                        }
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: heroShopId, slotId: slot.id } });
                    }
                    continue;
                }

                //Купить второго героя
                if (slot.reward.invasionFragmentHero?.[heroIds[1]] && heroFragments[1] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: heroShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: heroShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплен герой ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        heroFragments[1] += slot.reward.invasionFragmentHero?.[heroIds[1]];
                        //Если cо вторым титаном есть третий
                        if (slot.reward.invasionFragmentHero?.[heroIds[2]]) {
                            console.log('%cТретий герой в комплекте ', 'color: green; font-weight: bold;');
                            heroFragments[2] += slot.reward.invasionFragmentHero?.[heroIds[2]];
                        }
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: heroShopId, slotId: slot.id } });
                    }
                    continue;
                }
                //Купить третьего героя
                if (slot.reward.invasionFragmentHero?.[heroIds[2]] && heroFragments[2] < 7) {
                    if (coins >= slot.cost.coin[1080]) {
                        let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: heroShopId, slot: slot.id } });
                        if (shopBuy.error) {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: heroShopId, slotId: slot.id } });
                            coins = 0;
                            continue;
                        }
                        console.log('%cКуплен герой ', 'color: green; font-weight: bold;');
                        coins -= slot.cost.coin[1080];
                        heroFragments[2] += slot.reward.invasionFragmentHero?.[heroIds[2]];
                    } else {
                        await Caller.send({ name: 'shop_pinSlot', args: { shopId: heroShopId, slotId: slot.id } });
                    }
                    continue;
                }
                //Потратить оставшиеся монеты, если герои уже куплены
                if (heroFragments[0] >= 7 && heroFragments[1] >= 7 && heroFragments[2] >= 7) {
                    console.log('Тратим монеты');
                    if (slot.reward.invasionFragmentPet && petCounter[0] < 10) {
                        if (coins >= slot.cost.coin[1080]) {
                            await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: heroShopId, slot: slot.id } });
                            coins -= slot.cost.coin[1080];
                            petCounter[0]++;
                            console.log('%cКуплен питомец ', 'color: green; font-weight: bold;');
                        } else {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: heroShopId, slotId: slot.id } });
                        }
                    }
                    if (petCounter[0] >= 10) {
                        console.log('%cВсе питомцы куплены, переходим к покупке следующих героев', 'color: green; font-weight: bold;');
                        return true;
                    }
                }
            }
            //Обновить магазин
            if (coins >= 15) {
                shopSlots = await Caller.send({ name: 'shopRefresh', args: { shopId: heroShopId } }).then((e) => Object.values(e.slots));
                coins -= 3;
                console.log('Обновили магазин. Осталось монет ' + coins);
                if (shopSlots.error) {
                    coins = 0;
                }
            } else {
                break;
            }
        }
        return false;
    }

    async function buyTitansAndTotemSkils (shopId, titanIds, titanFragments, titanSkilsIds, titanSkilFragments) {
        console.log('Зашли в магазин');
        console.log('titanIds ', JSON.stringify(titanIds));
        console.log('titanFragments ', JSON.stringify(titanFragments));
        console.log('titanSkilsIds ', JSON.stringify(titanSkilsIds));
        console.log('titanSkilFragments ', JSON.stringify(titanSkilFragments));

        let coins = await Caller.send('inventoryGet').then((e) => e.coin[1080]);
        console.log('Монеты: ' + coins);

        let shopSlots = null;

        while (coins >= 9) {
            //Получить состояние магазина
            if (!shopSlots) {
                shopSlots = await Caller.send([{ name: 'shopGet', args: { shopId: shopId } }]).then((e) => Object.values(e.slots));
            }
            for (let slot of shopSlots) {
                //Пропустить скрытые лоты
                if (slot.reward.invasionFragmentTitanRand || slot.reward.invasionFragmentSkillRand) {
                    continue;
                }
                let boughtTitan = false;
                //Купить титанов
                for (let t = 0; t < titanIds.length; t++) {
                    if (slot.reward.invasionFragmentTitan?.[titanIds[t]] && titanFragments[t] < 7) {
                        if (coins >= slot.cost.coin[1080]) {
                            let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: shopId, slot: slot.id } });
                            console.log('%cКуплен титан ', 'color: green; font-weight: bold;');
                            coins -= slot.cost.coin[1080];
                            titanFragments[t] += slot.reward.invasionFragmentTitan?.[titanIds[t]];

                            //Если c первым титаном есть другой
                            for (let i = t+1; i < titanIds.length; i++) {
                                if (slot.reward.invasionFragmentTitan?.[titanIds[i]]) {
                                    console.log('%cВторой титан в комплекте ', 'color: green; font-weight: bold;');
                                    titanFragments[i] += slot.reward.invasionFragmentTitan?.[titanIds[i]];
                                    break;
                                }
                            }
                        } else {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: shopId, slotId: slot.id } });
                        }
                        boughtTitan = true;
                        break;
                    }
                }

                //Купить навыки тотема
                if (!boughtTitan) {
                    for (let s = 0; s < titanSkilsIds.length; s++) {
                        if (slot.reward.invasionFragmentSkill?.[titanSkilsIds[s]] && titanSkilFragments[s] < 7) {
                            if (coins >= slot.cost.coin[1080]) {
                                let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: shopId, slot: slot.id } });
                                console.log('%cКуплена часть навыка тотема ', 'color: green; font-weight: bold;');
                                coins -= slot.cost.coin[1080];
                                titanSkilFragments[s] += slot.reward.invasionFragmentSkill?.[titanSkilsIds[s]];
                            } else {
                                await Caller.send({ name: 'shop_pinSlot', args: { shopId: shopId, slotId: slot.id } });
                            }
                            break;
                        }
                    }
                }

                //Если ТИТАНЫ и тотемы собраны
                let titanF = false;
                let titanS = false;
                for (let tf of titanFragments) {
                    if (tf < 7) {
                        titanF = false;
                        break;
                    }
                    titanF = true;
                }
                for (let ts of titanSkilFragments) {
                    if (ts < 7) {
                        titanS = false;
                        break;
                    }
                    titanS = true;
                }
                if ( titanF && titanS) {
                    return;
                }
            }
            //Обновить магазин
            if (coins >= 12) {
                shopSlots = await Caller.send([{ name: 'shopRefresh', args: { shopId: shopId } }]).then((e) => Object.values(e.slots));
                coins -= 3;
                console.log('Обновили магазин. Осталось монет: ' + coins);
                if (shopSlots.error) {
                    coins = 0;
                }
            } else {
                break;
                return;
            }
        }
    }

    async function buyHeroesAndPets (shopId, heroIds, heroFragments, pets) {
        console.log('Зашли в магазин');
        console.log('heroIds ', JSON.stringify(heroIds));
        console.log('heroFragments ', JSON.stringify(heroFragments));
        console.log('pets ', JSON.stringify(pets));


        let coins = await Caller.send('inventoryGet').then((e) => e.coin[1080]);
        console.log('Монеты: ' + coins);

        let shopSlots = null;

        while (coins >= 9) {
            //Получить состояние магазина
            if (!shopSlots) {
                shopSlots = await Caller.send([{ name: 'shopGet', args: { shopId: shopId } }]).then((e) => Object.values(e.slots));
            }
            for (let slot of shopSlots) {
                //Пропустить скрытые лоты
                if (slot.reward.invasionFragmentHeroRand) {
                    continue;
                }
                let boughtHero = false;
                //Купить героев
                for (let t = 0; t < heroIds.length; t++) {
                    if (slot.reward.invasionFragmentHero?.[heroIds[t]] && heroFragments[t] < 7) {
                        if (coins >= slot.cost.coin[1080]) {
                            let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: shopId, slot: slot.id } });
                            console.log('%cКуплен герой ', 'color: green; font-weight: bold;');
                            coins -= slot.cost.coin[1080];
                            heroFragments[t] += slot.reward.invasionFragmentHero?.[heroIds[t]];

                            //Если c первым героем есть другой
                            for (let i = t+1; i < heroIds.length; i++) {
                                if (slot.reward.invasionFragmentHero?.[heroIds[i]]) {
                                    console.log('%cВторой герой в комплекте ', 'color: green; font-weight: bold;');
                                    heroFragments[i] += slot.reward.invasionFragmentHero?.[heroIds[i]];
                                    break;
                                }
                            }
                        } else {
                            await Caller.send({ name: 'shop_pinSlot', args: { shopId: shopId, slotId: slot.id } });
                        }
                        boughtHero = true;
                        break;
                    }
                }

                //Купить питомцев
                if (!boughtHero) {
                    for (let s = 0; s < pets.length; s++) {
                        if (slot.reward.invasionFragmentPet?.[pets[s]] && pets.length > 0) {
                            if (coins >= slot.cost.coin[1080]) {
                                let shopBuy = await Caller.send({ name: 'shopBuy', args: { cost: {}, reward: {}, shopId: shopId, slot: slot.id } });
                                console.log('%cКуплен питомец ', 'color: green; font-weight: bold;');
                                coins -= slot.cost.coin[1080];
                                pets = pets.filter((e) => e !== pets[s])
                            } else {
                                await Caller.send({ name: 'shop_pinSlot', args: { shopId: shopId, slotId: slot.id } });
                            }
                            break;
                        }
                    }
                }

                //Если ГЕРОИ и питомцы собраны
                let heroF = false;
                for (let tf of heroFragments) {
                    if (tf < 7) {
                        heroF = false;
                        break;
                    }
                    heroF = true;
                }
                if ( heroF && pets.length == 0) {
                    return;
                }
            }
            //Обновить магазин
            if (coins >= 15) {
                shopSlots = await Caller.send([{ name: 'shopRefresh', args: { shopId: shopId } }]).then((e) => Object.values(e.slots));
                coins -= 3;
                console.log('Обновили магазин. Осталось монет: ' + coins);
                if (shopSlots.error) {
                    coins = 0;
                }
            } else {
                break;
                return;
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    async function attackTitanMission(missionId, chapterId, heroes, firstSpiritSkills, boss = false) {
        console.log('heroes ', JSON.stringify(heroes));
        console.log('firstSpiritSkills ', JSON.stringify(firstSpiritSkills));
        const startBattle = await Caller.send({
            name: 'invasion_bossStart',
            args: {
                id: missionId,
                chapterId: chapterId,
                heroes: heroes,
                //firstSpiritElement: "earth",
                firstSpiritSkills: firstSpiritSkills,
                favor: {},
            },
        });
        const calcBattle = await Calc(startBattle);

        if (!calcBattle.result.win) {
            const cloneBattle = structuredClone(startBattle);
            const bFix = new WinFixBattle(cloneBattle);
            let result = await bFix.start(cloneBattle.endTime, Infinity);
            if (result.result?.win) {
                calcBattle.result = result.result;
                calcBattle.progress = result.progress;
                calcBattle.battleTimer = result.battleTimer;
            }
        }

        if (!calcBattle.result.win && boss == true) {
            //Босса не убили
            console.log('%cБосса не убили ', 'color: red; font-weight: bold;');
            return;
        }
        if (boss == true) {
            let timer = calcBattle.battleTimer * 1.2;
            console.log('%cУбили босса', 'color: green; font-weight: bold;');
            await countdownTimer(timer, `${I18N('NEWTITAN_BOSSWASKILLED')}`);
        }

        const endBattle = await Caller.send({
            name: 'invasion_bossEnd',
            args: {
                id: missionId,
                result: calcBattle.result,
                progress: calcBattle.progress,
            },
        });
    }

    async function attackHeroMission(missionId, chapterId, heroes, pet, boss = false) {
        const startBattle = await Caller.send({
            name: 'invasion_bossStart',
            args: {
                id: missionId,
                chapterId: chapterId,
                heroes: heroes,
                pet: pet,
                favor: {},
            },
        });
        const calcBattle = await Calc(startBattle);

        if (!calcBattle.result.win) {
            const cloneBattle = structuredClone(startBattle);
            const bFix = new WinFixBattle(cloneBattle);
            let result = await bFix.start(cloneBattle.endTime, Infinity);
            if (result.result?.win) {
                calcBattle.result = result.result;
                calcBattle.progress = result.progress;
                calcBattle.battleTimer = result.battleTimer;
            }
        }

        if (!calcBattle.result.win && boss == true) {
            //Босса не убили
            console.log('%cБосса не убили ', 'color: red; font-weight: bold;');
            return;
        }
        if (boss == true) {
            let timer = calcBattle.battleTimer * 1.2;
            console.log('%cУбили босса', 'color: green; font-weight: bold;');
            await countdownTimer(timer, `${I18N('NEWTITAN_BOSSWASKILLED')}`);
        }

        await Caller.send({
            name: 'invasion_bossEnd',
            args: {
                id: missionId,
                result: calcBattle.result,
                progress: calcBattle.progress,
            },
        });
    }
})();