package shot import ( "context" "fmt" // "log" "strconv" "strings" "time" "wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/shot/damage" "wartank/server/serv_bots/warbot/angar/division/divwar/divwaron/shottime" // "wartank/internal/components/sound" "wartank/pkg/alias" "wartank/pkg/components/safe_bool" "wartank/pkg/types" ) /* Исходник предоставляет выстрел со свойствами: - время до выстрела - длительность перезарядки Первый параметр постоянно изменяется (после выстрела восстанавливается) Второй параметр меняется медленно (в зависимости от количества очков после выстрела) */ // Shot -- объект выстрела type Shot struct { types.ИДивизияВойнаДействие // FIXME: recharge *shottime.ShotTime // Сколько времени нужно для полной перезарядки damage *damage.Damage // Урон от выстрела с памятью damageSum alias.Урон // Суммарный урон isEnd *safe_bool.БезопБул // Признак конца сражения login string // Логин для поиска контрольных строк chTick chan int // Тик для выстрела ctxEnd context.Context // Признак окончания сражения } // NewShot -- возвращает новый *Shot func NewShot(divWar types.ИДивизияВойнаДействие, login string) (*Shot, error) { { // Предусловия if divWar == nil { return nil, fmt.Errorf("NewShot(): battle is nil") } if login == "" { return nil, fmt.Errorf("NewShot(): login is empty") } } сам := &Shot{ ИДивизияВойнаДействие: divWar, ctxEnd: divWar.Ctx(), recharge: shottime.NewShotTime(), damage: damage.NewDamage(), isEnd: divWar.ЕслиКонец(), login: login, chTick: make(chan int, 2), } // Установить время перезарядки сам.recharge.Set(6800) go сам.makeTick() go сам.run() return сам, nil } // Генерирует тики, когда можно стрелять func (сам *Shot) makeTick() { defer func() { сам.isEnd.Уст() close(сам.chTick) сам.CancelBattle() // log._rintf("Shot.makeTick(): сражение завершёно\n") }() countMasking := 0 for { select { case <-сам.ctxEnd.Done(): return default: if сам.isEnd.Получ() { // Битва закончилась return } switch сам.ВыстрелБлок().Получ() { // Проверить запрет на стрельбу при слабом здоровье case true: // log._rintf("WARN Shot.run(): запрет на выстрел\n") countMasking++ if countMasking >= 200 { return } сам.Манёвр() time.Sleep(time.Millisecond * 500) continue default: countMasking = 0 } сам.chTick <- 1 // Здесь же первый выстрел recharge := сам.recharge.Get() // log._rintf("INFO Shot.run() перезарядка=%v msec\n", recharge) // Если идёт перезарядка -- постепенно обнуляем время ожидания time.Sleep(time.Millisecond * time.Duration(recharge)) } } } // Цикл выстрела (в отдельном потоке) func (сам *Shot) run() { for { select { case <-сам.ctxEnd.Done(): return case <-сам.chTick: // Стрелять можно, стандартное ожидание сам.shot() сам.findDamage() } } } // Обновляет возможность выстрела (~) // // Вызывается из отдельного потока func (сам *Shot) shot() { if err := сам.Сеть().Обновить(); err != nil { // Проверка на непосредственно битву // закончилась 00:00:07 назад // log._rintf("ERRO Shot.shot(): при обновлении lstBattleOn, err=\n\t%v\n", err) сам.isEnd.Уст() сам.CancelBattle() return } var ( strOut string lstBattle = сам.СписПолучить() еслиНайдено bool err error ) // ОБЫЧНЫЕ for _, strOut = range lstBattle { if strings.Contains(strOut, `-currentControl-attackRegularShellLink`) { еслиНайдено = true break } } if !еслиНайдено { // log._rintf("WARN Shot.shot(): не найдены ссылка на выстрел\n") сам.isEnd.Уст() сам.CancelBattle() return } lstLink := strings.Split(strOut, `ОБЫЧНЫЕ`) strLink = "https://wartank.ru/" + lstLink[0] lstBattle, err = сам.Сеть().Get(strLink) if err != nil { // log._rintf("ERRO Shot.shot(): при исполнении GET-команды выстрела обычным снарядом, err=\n\t%v\n", err) сам.isEnd.Уст() сам.CancelBattle() return } if err = сам.СтрОбновить(lstBattle); err != nil { // log._rintf("ERRO Shot.shot(): при обновлении lstBattle, err=\n\t%v\n", err) сам.isEnd.Уст() сам.CancelBattle() return } // sound.Shot() сам.Манёвр() } // Ищет урон от выстрела func (сам *Shot) findDamage() { var ( ind = 0 еслиНайдено = false lstShot = сам.СписПолучить() strOut string ) for ind, strOut = range lstShot { // prospero tank if strings.Contains(strOut, ``+сам.login+``) { ind += 2 strOut = lstShot[ind] еслиНайдено = true break } } if !еслиНайдено { // Возможно был рикошет или манёвр // log._rintf("WARN Shot.findDamage(): не найден урон от выстрела, strOut=%q, ind=%v\n", strOut, ind) return } lstDamage := strings.Split(strOut, ` на `) if len(lstDamage) == 1 { return } strDamage := lstDamage[1] iDamage, err := strconv.Atoi(strDamage) if err != nil { // log._rintf("ERRO Shot.findDamage(): damage(%v) не число, err=\n\t%v\n", strDamage, err) return } if iDamage <= 0 { // Кривой урон от выстрела сам.recharge.Dec5() // log._rintf("WARN Shot.findDamage(): ошибка в значении урона(%v)\n", iDamage) iDamage = 0 } сам.damageSum += alias.Урон(iDamage) // log._rintf("INFO Shot.Damage(): damageSum=%v\n", сам.damageSum) if iDamage < 70 { сам.damage.Set(alias.Урон(iDamage)) сам.recharge.Inc210() } // log._rintf("INFO Shot.findDamage(): выстрел=+%v, урон=%v", iDamage, сам.damageSum) if iDamage == 0 { return } сам.setDamage(alias.Урон(iDamage)) } // setDamage -- обновляет время перезарядки в зависимости от произведённого урона func (сам *Shot) setDamage(val alias.Урон) { сам.damage.Set(val) switch сам.damage.Result() { case "none": сам.recharge.Dec5() case "up": сам.recharge.Dec30() case "down": сам.recharge.Inc210() } } // IsEnd -- возвращает объект разрешения стрельбы func (сам *Shot) IsEnd() *safe_bool.БезопБул { return сам.isEnd }