package health import ( // "log" // "strconv" "strings" "time" . "wartank/app/lev0/types" "wartank/app/lev1/health/health_time" "wartank/app/lev1/repair_time" // "wartank/internal/components/sound" . "gitp78su.ipnodns.ru/svi/kern" . "gitp78su.ipnodns.ru/svi/kern/kc/helpers" . "gitp78su.ipnodns.ru/svi/kern/krn/ktypes" ) /* Контролирует состояние здоровья танка */ // Здоровье -- контроль здоровья танка type Здоровье struct { ИСражениеПроцесс // FIXME: fnCancel func() temp *health_time.HealthTime // Изменяемое здоровье танка full *health_time.HealthTime // Полное здоровье танка isRepair ISafeBool // Необходимость восстановления repairTime *repair_time.RepairTime // Время до восстановления isEnd ISafeBool // Ссылка на признак конца сражения login string // Для поиска контрольных строк chTick chan int // Канал для ровной отправки тиков // deltaOld int // Старая дельта потери здоровья // countLow int ctxBattle ILocalCtx // Контекст сражения } // НовЗдоровье -- возвращает новый *Health func НовЗдоровье(проц ИСражениеПроцесс) *Здоровье { Hassert(проц != nil, "НовЗдоровье(): ИСражениеПроцесс == nil") логин := проц.Бот().Имя() сам := &Здоровье{ ИСражениеПроцесс: проц, fnCancel: проц.Отменить, ctxBattle: проц.Бот().КонтБот(), temp: health_time.NewHealthTime(), full: health_time.NewHealthTime(), isRepair: NewSafeBool(), repairTime: repair_time.NewRepairTime(), isEnd: проц.ЕслиКонец(), login: логин, chTick: make(chan int, 2), } go сам.makeTik() go сам.run() return сам } // Отправляет тики с заданным равным интервалом func (сам *Здоровье) makeTik() { defer func() { сам.fnCancel() close(сам.chTick) // log._rintf("Health.makeTick(): сражение завершёно\n") }() count := 0 repairTime := 0 for { select { case <-сам.ctxBattle.Ctx().Done(): return default: if сам.ЕслиУбит() { return } if сам.repairTime.Get() == repairTime { count++ } else { repairTime = сам.repairTime.Get() count = 0 } if count > 90 { return } } сам.chTick <- 1 time.Sleep(time.Second * 1) сам.repairTime.Dec() } } // Главный цикл обработки здоровья в сражении func (сам *Здоровье) run() { for { select { case <-сам.ctxBattle.Ctx().Done(): сам.isEnd.Set() return case <-сам.chTick: // if err := сам.findHealth(); err != nil { // Найти свой здоровье // // log._rintf("ERRO Health.run(): при попытке найти здоровье, err=\n\t%v\n", err) // } сам.findRepairTime() if сам.Выстрел().ЕслиБлок() { if сам.isRepair.Get() { go сам.repair() } continue } if сам.isRepair.Get() { go сам.repair() } } } } // Full -- возвращает объект полного здоровья танка func (сам *Здоровье) Full() int { return сам.full.Get() } // ЕслиУбит -- возвращает признак мертвичины танка func (сам *Здоровье) ЕслиУбит() bool { if сам.isEnd.Get() { сам.fnCancel() return true } lstBattle := сам.СписПолучить() for _, strOut := range lstBattle { if strings.Contains(strOut, `>Ваш танк подбит.`) { // log._rintf("INFO Health.repair(): танк подбит\n") сам.temp.Set(0) сам.isEnd.Set() сам.fnCancel() return true } } return сам.isEnd.Get() } // Ищет время восстановления ремки func (сам *Здоровье) findRepairTime() { defer func() { if сам.repairTime.IsReady() { return } // if сам.repairTime.IsChange() { // log._rintf("INFO Health.findRepair(): до ремки=%v\n", сам.repairTime.Get()) // } }() if сам.repairTime.IsReady() { return } var ( strOut string lstBattle = сам.СписПолучить() еслиНайдено bool ind int ) // 12 секунд // for ind, strOut = range lstBattle { if !strings.Contains(strOut, `ILinkListener-currentControl-repairLink`) { continue } if strings.Contains(strOut, ` секунд`) { еслиНайдено = true break } } if !еслиНайдено { return } strOut = lstBattle[ind] // 12 секунд lstTime := strings.Split(strOut, `ILinkListener-currentControl-repairLink" class="simple-but blue">`) if len(lstTime) < 2 { // log._rintf("ERRO Health.findRepair(): при попытке получить ссылку на ремонт, strOut=\n%v\n", strOut) сам.isEnd.Set() сам.fnCancel() return } // strTime := lstTime[1] // lstTime = strings.Split(strTime, ` секунд`) // strTime = lstTime[0] // if err := сам.repairTime.Set(strTime); err != nil { // log._rintf("ERRO Health.findRepair(): при установке времени восстановления ремки, err=\n\t%v\n", err) // } } // Восстанавливает здоровье (~) func (сам *Здоровье) repair() { var ( strOut string lstBattleOn = сам.СписПолучить() еслиНайденоRepair bool ind int ) // Ремкомплект // Ремкомплект for ind, strOut = range lstBattleOn { if strings.Contains(strOut, `Ремкомплект`) { еслиНайденоRepair = true break } } if !еслиНайденоRepair { return } strOut = lstBattleOn[ind] // Ремкомплект lstLink := strings.Split(strOut, `Ремкомплект`) strLink = "https://wartank.ru/" + lstLink[0] lstBattleOn, err := сам.Сеть().Get(strLink) if err != nil { // log._rintf("ERRO Health.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", err) сам.isEnd.Set() сам.fnCancel() return } if err = сам.СтрОбновить(lstBattleOn); err != nil { // log._rintf("ERRO Health.repair(): при обновлении lstBattle, err=\n\t%v\n", err) сам.isEnd.Set() сам.Отменить() return } // sound.Repair() // log._rintf("INFO Health.repair(): здоровье восстановлено\n") } // Ищет своё здоровье (~) // func (сам *Health) findHealth() error { // var ( // ind int // strOut string // еслиНайдено bool // lstBattle = сам.СписПолучить() // ) // if len(lstBattle) == 0 { // Принудительно обновим сражение // if err := сам.Сеть().Обновить(); err != nil { // сам.isEnd.Уст() // сам.fnCancel() // return fmt.Errorf("Health.findHealth(): после принудительного обновления lsBattleOn, err=\n\t%w", err) // } // } // for ind, strOut = range lstBattle { // if strings.Contains(strOut, `alt="`+сам.login+`"`) { // еслиНайдено = true // break // } // } // if !еслиНайдено { // Свой танк не найден // сам.isEnd.Уст() // сам.fnCancel() // return fmt.Errorf("Health.findHealth(): своё здоровье не найдено") // } // // Свой танк найден, ищем здоровье // ind += 11 // strOut = lstBattle[ind] // lstHealth := strings.Split(strOut, `
`) // strHealth := lstHealth[1] // lstHealth = strings.Split(strHealth, `
`) // strHealth = lstHealth[0] // iHealth, err := strconv.Atoi(strHealth) // if err != nil { // сам.isEnd.Уст() // сам.CancelBattle() // return fmt.Errorf("Health.findHealth(): здоровье(%v) не число, err=%w", strHealth, err) // } // сам.setHealth(iHealth) // return nil // } // setHealth -- устанавливает текущее здоровье // func (сам *Health) setHealth(val int) { // if val < 0 { // // log._rintf("WARN Health.setHealth(): кривое значение здоровья танка(%v)\n", val) // val = 0 // } // if val > сам.full.Get() { // // log._rintf("WARN Health.setHealth(): кривое текущее здоровье, %v/%v\n", val, сам.full.Get()) // сам.full.Set(val) // сам.temp.Set(val) // // сам.deltaOld = 0 // сам.ВыстрелБлок().Сброс() // сам.isRepair.Сброс() // return // } // delta := сам.temp.Get() - val // // if delta > 0 { // Дельта будет больше нуля, если только // // if delta != сам.deltaOld { // // // log._rintf("INFO Health.setHealth(): потеря здоровья=%v/%v\n", -delta, val) // // сам.deltaOld = delta // // сам.temp.Set(val) // // } // // } // switch { // case сам.isEnd.Получ(): // сам.temp.Set(0) // сам.isEnd.Уст() // сам.CancelBattle() // return // case val == 0: // сам.temp.Set(0) // сам.isEnd.Уст() // сам.CancelBattle() // return // case val <= 500: // Запретить стрельбу // сам.ВыстрелБлок().Уст() // Установить запрет стрельбы пока слабое здоровье // сам.isRepair.Уст() // // log._rintf("WARN Health.setHealth(): низкий уровень здоровья(%v)\n", val) // сам.Манёвр() // case val > 500: // Разрешить стрельбы // сам.ВыстрелБлок().Сброс() // сам.isRepair.Сброс() // if delta > сам.full.Get()*4/10 { // Проверить на критичность падения здоровья на 40% // // log._rintf("WARN Health.setHealth(): большая разовая потеря здоровья(%v)\n", delta) // сам.Манёвр() // сам.isRepair.Уст() // return // } // } // isMask := сам.ВыстрелБлок().Получ() // switch isMask { // case true: // // сам.countLow++ // // if сам.countLow >= 200 { // // сам.isEnd.Уст() // // сам.CancelBattle() // // return // // } // default: // // сам.countLow = 0 // } // if val == сам.full.Get() { // сам.temp.Set(val) // сам.isRepair.Сброс() // сам.ВыстрелБлок().Сброс() // // сам.countLow = 0 // } // }