package shot
import (
"strconv"
"strings"
"time"
. "wartank/app/lev0/types"
"wartank/app/lev1/shot/damage"
"wartank/app/lev1/shot/shot_time"
// "wartank/internal/components/sound"
"wartank/app/lev0/alias"
. "gitp78su.ipnodns.ru/svi/kern"
. "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
. "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
)
/*
Исходник предоставляет выстрел со свойствами:
- время до выстрела
- длительность перезарядки
Первый параметр постоянно изменяется (после выстрела восстанавливается)
Второй параметр меняется медленно (в зависимости от количества очков после выстрела)
*/
// выстрел -- объект выстрела
type выстрел struct {
ИСражениеПроцесс // FIXME:
перезарядка *shot_time.ShotTime // Сколько времени нужно для полной перезарядки
урон *damage.Damage // Урон от выстрела с памятью
уронВсего alias.АУрон // Суммарный урон
isEnd ISafeBool // Признак конца сражения
еслиБлок ISafeBool // Признак блокировки выстрела
логин string // Логин для поиска контрольных строк
chTick chan int // Тик для выстрела
}
// НовВыстрел -- возвращает новый выстрел
func НовВыстрел(проц ИСражениеПроцесс) ИВыстрел {
Hassert(проц != nil, "НовВыстрел(): ИСражениеПроцесс == nil")
логинТанк := проц.Бот().Имя()
сам := &выстрел{
ИСражениеПроцесс: проц,
перезарядка: shot_time.NewShotTime(),
урон: damage.NewDamage(),
еслиБлок: NewSafeBool(),
isEnd: проц.ЕслиКонец(),
логин: логинТанк,
chTick: make(chan int, 2),
}
// Установить время перезарядки
сам.перезарядка.Set(6800)
go сам.makeTick()
go сам.run()
return сам
}
// БлокУст -- установка блокировки выстрела
func (сам *выстрел) БлокУст() {
сам.еслиБлок.Set()
}
// БлокСброс -- сброс блокировки выстрела
func (сам *выстрел) БлокСброс() {
сам.еслиБлок.Reset()
}
// ЕслиБлок -- возвращает признак блокировки выстрела
func (сам *выстрел) ЕслиБлок() bool {
return сам.еслиБлок.Get()
}
// Генерирует тики, когда можно стрелять
func (сам *выстрел) makeTick() {
defer func() {
сам.isEnd.Set()
close(сам.chTick)
сам.Отменить()
// log._rintf("Shot.makeTick(): сражение завершёно\n")
}()
countMasking := 0
for {
select {
case <-сам.Контекст().Done():
return
default:
if сам.isEnd.Get() { // Битва закончилась
return
}
switch сам.еслиБлок.Get() { // Проверить запрет на стрельбу при слабом здоровье
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 := сам.перезарядка.Get()
// log._rintf("INFO Shot.run() перезарядка=%v msec\n", recharge)
// Если идёт перезарядка -- постепенно обнуляем время ожидания
time.Sleep(time.Millisecond * time.Duration(recharge))
}
}
}
// Цикл выстрела (в отдельном потоке)
func (сам *выстрел) run() {
for {
select {
case <-сам.Контекст().Done():
return
case <-сам.chTick:
// Стрелять можно, стандартное ожидание
сам.shot()
сам.findDamage()
}
}
}
// Обновляет возможность выстрела (~)
//
// Вызывается из отдельного потока
func (сам *выстрел) shot() {
сам.Обновить()
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.Set()
сам.Бот().КонтБот().Cancel()
return
}
strLink := strings.TrimPrefix(strOut, `ОБЫЧНЫЕ`)
strLink = "https://wartank.ru/" + strLink
lstBattle, err = сам.Сеть().Get(strLink)
if err != nil {
// log._rintf("ERRO Shot.shot(): при исполнении GET-команды выстрела обычным снарядом, err=\n\t%v\n", err)
сам.isEnd.Set()
сам.Бот().КонтБот().Cancel()
return
}
сам.СтрОбновить(lstBattle)
// sound.Shot()
сам.Манёвр()
}
// Ищет урон от выстрела
func (сам *выстрел) findDamage() {
var (
ind int
еслиНайдено bool
lstShot = сам.СписПолучить()
strOut string
)
for ind, strOut = range lstShot {
// prospero tank
if strings.Contains(strOut, ``+сам.логин+``) {
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 { // Кривой урон от выстрела
сам.перезарядка.Dec5()
// log._rintf("WARN Shot.findDamage(): ошибка в значении урона(%v)\n", iDamage)
iDamage = 0
}
сам.уронВсего += alias.АУрон(iDamage)
// log._rintf("INFO Shot.Damage(): damageSum=%v\n", сам.damageSum)
if iDamage < 70 {
сам.урон.Set(alias.АУрон(iDamage))
сам.перезарядка.Inc210()
}
// log._rintf("INFO Shot.findDamage(): выстрел=+%v, урон=%v", iDamage, сам.damageSum)
if iDamage == 0 {
return
}
сам.setDamage(alias.АУрон(iDamage))
}
// setDamage -- обновляет время перезарядки в зависимости от произведённого урона
func (сам *выстрел) setDamage(val alias.АУрон) {
сам.урон.Set(val)
switch сам.урон.Result() {
case "none":
сам.перезарядка.Dec5()
case "up":
сам.перезарядка.Dec30()
case "down":
сам.перезарядка.Inc210()
}
}
// IsEnd -- возвращает объект разрешения стрельбы
func (сам *выстрел) IsEnd() ISafeBool {
return сам.isEnd
}