| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290 |
- package health
- import (
- "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:
- здоровьеСейчас *health_time.HealthTime // Изменяемое здоровье танка
- здоровьеПолное *health_time.HealthTime // Полное здоровье танка
- еслиНадо ISafeBool // Необходимость восстановления
- отсчётАптечка *repair_time.RepairTime // Время до восстановления
- isEnd ISafeBool // Ссылка на признак конца сражения
- логин string // Для поиска контрольных строк
- chTick chan int // Канал для ровной отправки тиков
- // deltaOld int // Старая дельта потери здоровья
- // countLow int
- }
- // НовЗдоровье -- возвращает новый *Health
- func НовЗдоровье(проц ИСражениеПроцесс) *Здоровье {
- Hassert(проц != nil, "НовЗдоровье(): ИСражениеПроцесс == nil")
- логин := проц.Бот().Имя()
- сам := &Здоровье{
- ИСражениеПроцесс: проц,
- здоровьеСейчас: health_time.NewHealthTime(),
- здоровьеПолное: health_time.NewHealthTime(),
- еслиНадо: NewSafeBool(),
- отсчётАптечка: repair_time.NewRepairTime(),
- isEnd: проц.ЕслиКонец(),
- логин: логин,
- chTick: make(chan int, 2),
- }
- go сам.makeTik()
- go сам.run()
- return сам
- }
- // Отправляет тики с заданным равным интервалом
- func (сам *Здоровье) makeTik() {
- defer func() {
- close(сам.chTick)
- сам.Отменить()
- }()
- лимитАптечка := 0 // Предел времени ожидания
- отсчётАптечка := 0
- for {
- select {
- case <-сам.Контекст().Done():
- return
- default:
- if сам.ЕслиУбит() {
- return
- }
- if сам.отсчётАптечка.Получ() == отсчётАптечка {
- лимитАптечка++
- } else {
- отсчётАптечка = сам.отсчётАптечка.Получ()
- лимитАптечка = 0
- }
- if сам.отсчётАптечка.IsReady() {
- лимитАптечка = 0
- }
- if лимитАптечка > 90 {
- return
- }
- }
- сам.chTick <- 1
- time.Sleep(time.Second * 1)
- сам.отсчётАптечка.Dec()
- }
- }
- // Главный цикл обработки здоровья в сражении
- func (сам *Здоровье) run() {
- for {
- select {
- case <-сам.Контекст().Done():
- сам.isEnd.Set()
- return
- case <-сам.chTick:
- сам.здоровьеНайти()
- сам.найтиВремяВосстановления()
- if сам.еслиНадо.Get() {
- go сам.repair()
- }
- }
- }
- }
- // Полное -- возвращает объект полного здоровья танка
- func (сам *Здоровье) Полное() int {
- return сам.здоровьеПолное.Get()
- }
- // ЕслиУбит -- возвращает признак мертвичины танка
- func (сам *Здоровье) ЕслиУбит() bool {
- if сам.isEnd.Get() {
- сам.Отменить()
- return true
- }
- lstBattle := сам.СписПолучить()
- for _, strOut := range lstBattle {
- if strings.Contains(strOut, `>Ваш танк подбит.`) {
- сам.здоровьеСейчас.Set(0)
- сам.isEnd.Set()
- сам.Отменить()
- return true
- }
- }
- return сам.isEnd.Get()
- }
- // Ищет время восстановления ремки
- func (сам *Здоровье) найтиВремяВосстановления() {
- if сам.отсчётАптечка.IsReady() {
- return
- }
- var (
- strOut string
- lstBattle = сам.СписПолучить()
- еслиНайдено bool
- ind int
- )
- // <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>12 секунд</span></span></a>
- //
- for ind, strOut = range lstBattle {
- if strings.Contains(strOut, `ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>`) {
- еслиНайдено = true
- break
- }
- }
- if !еслиНайдено {
- return
- }
- strOut = lstBattle[ind]
- // <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>12 секунд</span></span></a>
- lstTime := strings.Split(strOut, `ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>`)
- if len(lstTime) < 2 {
- сам.isEnd.Set()
- сам.Отменить()
- return
- }
- strTime := lstTime[1]
- strTime = strings.TrimSuffix(strTime, ` секунд</span></span></a>`)
- if err := сам.отсчётАптечка.Уст(strTime); err != nil {
- сам.isEnd.Set()
- сам.Отменить()
- return
- }
- }
- // Восстанавливает здоровье (~)
- func (сам *Здоровье) repair() {
- var (
- strOut string
- lstBattleOn = сам.СписПолучить()
- еслиНайденоRepair bool
- ind int
- )
- // <span>Ремкомплект</span>
- // <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>Ремкомплект</span></span></a>
- for ind, strOut = range lstBattleOn {
- if strings.Contains(strOut, `<span>Ремкомплект</span>`) {
- еслиНайденоRepair = true
- break
- }
- }
- if !еслиНайденоRepair {
- return
- }
- strOut = lstBattleOn[ind]
- // <a href="pve?6-26.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>Ремкомплект</span></span></a>
- lstLink := strings.Split(strOut, `<a href="`)
- strLink := lstLink[1]
- lstLink = strings.Split(strLink, `" class="simple-but blue"><span><span>Ремкомплект</span></span></a>`)
- strLink = "https://wartank.ru/" + lstLink[0]
- res := сам.Сеть().Get(strLink)
- if res.IsErr() {
- // log._rintf("ERRO Health.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", res.Error())
- сам.isEnd.Set()
- сам.Отменить()
- return
- }
- lstBattleOn = res.Unwrap()
- сам.СтрОбновить(lstBattleOn)
- // sound.Repair()
- }
- // Ищет своё здоровье (~)
- func (сам *Здоровье) здоровьеНайти() {
- var (
- ind int
- strOut string
- еслиНайдено bool
- lstBattle = сам.СписПолучить()
- )
- if len(lstBattle) == 0 { // Принудительно обновим сражение
- сам.Обновить()
- lstBattle = сам.СписПолучить()
- }
- // <div class="small bold green1 sh_b mb10 mt5">Половина коня</div>
- for ind, strOut = range lstBattle {
- if strings.Contains(strOut, `<div class="small bold green1 sh_b mb10 mt5">`+сам.логин+`"`) {
- еслиНайдено = true
- break
- }
- }
- if !еслиНайдено { // Свой танк не найден
- сам.isEnd.Set()
- сам.Отменить()
- return
- }
- // Свой танк найден, ищем здоровье
- // <div class="value-block lh1"><span><span>500</span></span></div>
- ind += 11
- strOut = lstBattle[ind]
- strHealth := strings.TrimPrefix(strOut, `<div class="value-block lh1"><span><span>`)
- strHealth = strings.TrimSuffix(strHealth, `</span></span></div>`)
- iHealth, err := strconv.Atoi(strHealth)
- if err != nil {
- сам.isEnd.Set()
- сам.Отменить()
- return
- }
- сам.здоровьеУстановить(iHealth)
- }
- // здоровьеУстановить -- устанавливает текущее здоровье
- func (сам *Здоровье) здоровьеУстановить(здоровье int) {
- if здоровье < 0 {
- // log._rintf("WARN Health.здоровьеУстановить(): кривое значение здоровья танка(%v)\n", val)
- здоровье = 0
- }
- дельта := сам.здоровьеСейчас.Get() - здоровье
- if дельта < 0 { // Такое может быть, если было лечение
- дельта = 0
- }
- if здоровье >= сам.здоровьеПолное.Get() {
- // log._rintf("WARN Health.здоровьеУстановить(): кривое текущее здоровье, %v/%v\n", val, сам.full.Get())
- сам.здоровьеПолное.Set(здоровье)
- сам.здоровьеСейчас.Set(здоровье)
- // сам.deltaOld = 0
- сам.Выстрел().БлокСброс()
- сам.еслиНадо.Reset()
- return
- }
- switch {
- case сам.isEnd.Get(): // Конец сражения
- сам.здоровьеСейчас.Set(0)
- сам.isEnd.Set()
- сам.Отменить()
- return
- case здоровье <= 0: // Убит
- сам.здоровьеСейчас.Set(0)
- сам.isEnd.Set()
- сам.Отменить()
- return
- case здоровье <= 500: // Запретить стрельбу
- сам.Выстрел().БлокУст() // Установить запрет стрельбы пока слабое здоровье
- сам.еслиНадо.Set()
- сам.Манёвр().УстНадо()
- case здоровье > 500: // Разрешить стрельбу
- сам.Выстрел().БлокСброс()
- сам.еслиНадо.Reset()
- if дельта > сам.здоровьеПолное.Get()*4/10 { // Проверить на критичность падения здоровья на 40%
- // log._rintf("WARN Health.здоровьеУстановить(): большая разовая потеря здоровья(%v)\n", delta)
- сам.Манёвр().УстНадо()
- сам.еслиНадо.Set()
- return
- }
- }
- }
|