HWHNewCharacterExt

Extension for HeroWarsHelper script

// ==UserScript==
// @name             HWHNewCharacterExt
// @name:en          HWHNewCharacterExt
// @name:ru          HWHNewCharacterExt
// @namespace        HWHNewCharacterExt
// @version          1.41
// @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>',
    };

    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>',
    };

    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 () {
            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')}`);
            }
        },
    });

    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();
                },
            },
            {
                get msg() {
                    return I18N('NEWTITAN_GETINFLUENCESKILL');
                },
                get title() {
                    return I18N('NEWTITAN_GETINFLUENCESKILL_TITLE');
                },
                result: async function () {
                    await newTitanGetInvasionFragmentSkill();
                },
            },
            {
                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')}`);
                    }
                },
            },
            {
                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',
            },
        ];
        popupButtons.push({ result: false, isClose: true });
        const answer = await popup.confirm(`${I18N('NEWTITAN')} ${I18N('NEWHERO_SELECTACTION')}`, popupButtons);
        if (typeof answer === 'function') {
            answer();
        }
    }

    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));

        //Сброс главы
        await Caller.send('invasion_resetChapter');

        //Получить 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 = [];
                haveTitanFragments = await Caller.send('invasion_getInfo').then((e) => e.fragments);
                for (let f in haveTitanFragments) {
                    //Исключаем фрагменты тотемов
                    if (Number(f) < 4400) {
                        heroes.push(Number(f));
                    }
                    if (heroes.length == 5) {
                        break;
                    }
                }
                let firstSpiritSkills = {};

                //Проходим миссию
                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));

        //Сброс главы
        await Caller.send('invasion_resetChapter');

        //Получить 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);
                //await new Promise((e) => setTimeout(e, 4000));
                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 = [];
                haveTitanFragments = await Caller.send('invasion_getInfo').then((e) => e.fragments);
                for (let f in haveTitanFragments) {
                    //Исключаем фрагменты тотемов
                    if (Number(f) < 4400) {
                        heroes.push(Number(f));
                    }
                    if (heroes.length == 5) {
                        break;
                    }
                }
                console.log(heroes);

                let firstSpiritSkills = {};

                //Проходим миссию
                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));

        //Сброс главы
        await Caller.send('invasion_resetChapter');

        //Получить 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);
                //await new Promise((e) => setTimeout(e, 4000));
                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 = [];
                haveHeroFragments = await Caller.send('invasion_getInfo').then((e) => e.fragments);
                for (let f in haveHeroFragments) {
                    //Исключаем питомцев
                    if (Number(f) < 6000) {
                        heroes.push(Number(f));
                    }
                    if (heroes.length == 5) {
                        break;
                    }
                }
                console.log('Атакующие герои ' + heroes);

                let pet;

                //Проходим миссию
                await attackTitanMission(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 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 attackTitanMission(missionId, chapterId, heroes, firstSpiritSkills, boss = false) {
        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;
            }
        }

        if (!calcBattle.result.win && boss == true) {
            //Босса не убили
            console.log('%cБосса не убили ', 'color: red; font-weight: bold;');
            return;
        }
        if (boss == true) {
            let timer = calcBattle.battleTimer + 10;
            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;
            }
        }

        if (!calcBattle.result.win && boss == true) {
            //Босса не убили
            console.log('%cБосса не убили ', 'color: red; font-weight: bold;');
            return;
        }
        if (boss == true) {
            let timer = calcBattle.battleTimer + 10;
            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,
            },
        });
    }
})();