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
}