health.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. package health
  2. import (
  3. // "log"
  4. // "strconv"
  5. "strings"
  6. "time"
  7. . "wartank/app/lev0/types"
  8. "wartank/app/lev1/health/health_time"
  9. "wartank/app/lev1/repair_time"
  10. // "wartank/internal/components/sound"
  11. . "gitp78su.ipnodns.ru/svi/kern"
  12. . "gitp78su.ipnodns.ru/svi/kern/kc/helpers"
  13. . "gitp78su.ipnodns.ru/svi/kern/krn/ktypes"
  14. )
  15. /*
  16. Контролирует состояние здоровья танка
  17. */
  18. // Здоровье -- контроль здоровья танка
  19. type Здоровье struct {
  20. ИСражениеПроцесс // FIXME:
  21. fnCancel func()
  22. temp *health_time.HealthTime // Изменяемое здоровье танка
  23. full *health_time.HealthTime // Полное здоровье танка
  24. isRepair ISafeBool // Необходимость восстановления
  25. repairTime *repair_time.RepairTime // Время до восстановления
  26. isEnd ISafeBool // Ссылка на признак конца сражения
  27. login string // Для поиска контрольных строк
  28. chTick chan int // Канал для ровной отправки тиков
  29. // deltaOld int // Старая дельта потери здоровья
  30. // countLow int
  31. ctxBattle ILocalCtx // Контекст сражения
  32. }
  33. // НовЗдоровье -- возвращает новый *Health
  34. func НовЗдоровье(проц ИСражениеПроцесс) *Здоровье {
  35. Hassert(проц != nil, "НовЗдоровье(): ИСражениеПроцесс == nil")
  36. логин := проц.Бот().Имя()
  37. сам := &Здоровье{
  38. ИСражениеПроцесс: проц,
  39. fnCancel: проц.Отменить,
  40. ctxBattle: проц.Бот().КонтБот(),
  41. temp: health_time.NewHealthTime(),
  42. full: health_time.NewHealthTime(),
  43. isRepair: NewSafeBool(),
  44. repairTime: repair_time.NewRepairTime(),
  45. isEnd: проц.ЕслиКонец(),
  46. login: логин,
  47. chTick: make(chan int, 2),
  48. }
  49. go сам.makeTik()
  50. go сам.run()
  51. return сам
  52. }
  53. // Отправляет тики с заданным равным интервалом
  54. func (сам *Здоровье) makeTik() {
  55. defer func() {
  56. сам.fnCancel()
  57. close(сам.chTick)
  58. // log._rintf("Health.makeTick(): сражение завершёно\n")
  59. }()
  60. count := 0
  61. repairTime := 0
  62. for {
  63. select {
  64. case <-сам.ctxBattle.Ctx().Done():
  65. return
  66. default:
  67. if сам.ЕслиУбит() {
  68. return
  69. }
  70. if сам.repairTime.Get() == repairTime {
  71. count++
  72. } else {
  73. repairTime = сам.repairTime.Get()
  74. count = 0
  75. }
  76. if count > 90 {
  77. return
  78. }
  79. }
  80. сам.chTick <- 1
  81. time.Sleep(time.Second * 1)
  82. сам.repairTime.Dec()
  83. }
  84. }
  85. // Главный цикл обработки здоровья в сражении
  86. func (сам *Здоровье) run() {
  87. for {
  88. select {
  89. case <-сам.ctxBattle.Ctx().Done():
  90. сам.isEnd.Set()
  91. return
  92. case <-сам.chTick:
  93. // if err := сам.findHealth(); err != nil { // Найти свой здоровье
  94. // // log._rintf("ERRO Health.run(): при попытке найти здоровье, err=\n\t%v\n", err)
  95. // }
  96. сам.findRepairTime()
  97. if сам.Выстрел().ЕслиБлок() {
  98. if сам.isRepair.Get() {
  99. go сам.repair()
  100. }
  101. continue
  102. }
  103. if сам.isRepair.Get() {
  104. go сам.repair()
  105. }
  106. }
  107. }
  108. }
  109. // Full -- возвращает объект полного здоровья танка
  110. func (сам *Здоровье) Full() int {
  111. return сам.full.Get()
  112. }
  113. // ЕслиУбит -- возвращает признак мертвичины танка
  114. func (сам *Здоровье) ЕслиУбит() bool {
  115. if сам.isEnd.Get() {
  116. сам.fnCancel()
  117. return true
  118. }
  119. lstBattle := сам.СписПолучить()
  120. for _, strOut := range lstBattle {
  121. if strings.Contains(strOut, `>Ваш танк подбит.`) {
  122. // log._rintf("INFO Health.repair(): танк подбит\n")
  123. сам.temp.Set(0)
  124. сам.isEnd.Set()
  125. сам.fnCancel()
  126. return true
  127. }
  128. }
  129. return сам.isEnd.Get()
  130. }
  131. // Ищет время восстановления ремки
  132. func (сам *Здоровье) findRepairTime() {
  133. defer func() {
  134. if сам.repairTime.IsReady() {
  135. return
  136. }
  137. // if сам.repairTime.IsChange() {
  138. // log._rintf("INFO Health.findRepair(): до ремки=%v\n", сам.repairTime.Get())
  139. // }
  140. }()
  141. if сам.repairTime.IsReady() {
  142. return
  143. }
  144. var (
  145. strOut string
  146. lstBattle = сам.СписПолучить()
  147. еслиНайдено bool
  148. ind int
  149. )
  150. // <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>12 секунд</span></span></a>
  151. //
  152. for ind, strOut = range lstBattle {
  153. if !strings.Contains(strOut, `ILinkListener-currentControl-repairLink`) {
  154. continue
  155. }
  156. if strings.Contains(strOut, ` секунд</span></span></a>`) {
  157. еслиНайдено = true
  158. break
  159. }
  160. }
  161. if !еслиНайдено {
  162. return
  163. }
  164. strOut = lstBattle[ind]
  165. // <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>12 секунд</span></span></a>
  166. lstTime := strings.Split(strOut, `ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>`)
  167. if len(lstTime) < 2 {
  168. // log._rintf("ERRO Health.findRepair(): при попытке получить ссылку на ремонт, strOut=\n%v\n", strOut)
  169. сам.isEnd.Set()
  170. сам.fnCancel()
  171. return
  172. }
  173. // strTime := lstTime[1]
  174. // lstTime = strings.Split(strTime, ` секунд</span></span></a>`)
  175. // strTime = lstTime[0]
  176. // if err := сам.repairTime.Set(strTime); err != nil {
  177. // log._rintf("ERRO Health.findRepair(): при установке времени восстановления ремки, err=\n\t%v\n", err)
  178. // }
  179. }
  180. // Восстанавливает здоровье (~)
  181. func (сам *Здоровье) repair() {
  182. var (
  183. strOut string
  184. lstBattleOn = сам.СписПолучить()
  185. еслиНайденоRepair bool
  186. ind int
  187. )
  188. // <span>Ремкомплект</span>
  189. // <a href="pve?19-14.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>Ремкомплект</span></span></a>
  190. for ind, strOut = range lstBattleOn {
  191. if strings.Contains(strOut, `<span>Ремкомплект</span>`) {
  192. еслиНайденоRepair = true
  193. break
  194. }
  195. }
  196. if !еслиНайденоRepair {
  197. return
  198. }
  199. strOut = lstBattleOn[ind]
  200. // <a href="pve?6-26.ILinkListener-currentControl-repairLink" class="simple-but blue"><span><span>Ремкомплект</span></span></a>
  201. lstLink := strings.Split(strOut, `<a href="`)
  202. strLink := lstLink[1]
  203. lstLink = strings.Split(strLink, `" class="simple-but blue"><span><span>Ремкомплект</span></span></a>`)
  204. strLink = "https://wartank.ru/" + lstLink[0]
  205. lstBattleOn, err := сам.Сеть().Get(strLink)
  206. if err != nil {
  207. // log._rintf("ERRO Health.repair(): при выполнении GET-команды ремонта, err=\n\t%v\n", err)
  208. сам.isEnd.Set()
  209. сам.fnCancel()
  210. return
  211. }
  212. сам.СтрОбновить(lstBattleOn)
  213. // sound.Repair()
  214. }
  215. // Ищет своё здоровье (~)
  216. // func (сам *Health) findHealth() error {
  217. // var (
  218. // ind int
  219. // strOut string
  220. // еслиНайдено bool
  221. // lstBattle = сам.СписПолучить()
  222. // )
  223. // if len(lstBattle) == 0 { // Принудительно обновим сражение
  224. // if err := сам.Сеть().Обновить(); err != nil {
  225. // сам.isEnd.Уст()
  226. // сам.fnCancel()
  227. // return fmt.Errorf("Health.findHealth(): после принудительного обновления lsBattleOn, err=\n\t%w", err)
  228. // }
  229. // }
  230. // for ind, strOut = range lstBattle {
  231. // if strings.Contains(strOut, `alt="`+сам.login+`"`) {
  232. // еслиНайдено = true
  233. // break
  234. // }
  235. // }
  236. // if !еслиНайдено { // Свой танк не найден
  237. // сам.isEnd.Уст()
  238. // сам.fnCancel()
  239. // return fmt.Errorf("Health.findHealth(): своё здоровье не найдено")
  240. // }
  241. // // Свой танк найден, ищем здоровье
  242. // ind += 11
  243. // strOut = lstBattle[ind]
  244. // lstHealth := strings.Split(strOut, `<div class="value-block lh1"><span><span>`)
  245. // strHealth := lstHealth[1]
  246. // lstHealth = strings.Split(strHealth, `</span></span></div>`)
  247. // strHealth = lstHealth[0]
  248. // iHealth, err := strconv.Atoi(strHealth)
  249. // if err != nil {
  250. // сам.isEnd.Уст()
  251. // сам.CancelBattle()
  252. // return fmt.Errorf("Health.findHealth(): здоровье(%v) не число, err=%w", strHealth, err)
  253. // }
  254. // сам.setHealth(iHealth)
  255. // return nil
  256. // }
  257. // setHealth -- устанавливает текущее здоровье
  258. // func (сам *Health) setHealth(val int) {
  259. // if val < 0 {
  260. // // log._rintf("WARN Health.setHealth(): кривое значение здоровья танка(%v)\n", val)
  261. // val = 0
  262. // }
  263. // if val > сам.full.Get() {
  264. // // log._rintf("WARN Health.setHealth(): кривое текущее здоровье, %v/%v\n", val, сам.full.Get())
  265. // сам.full.Set(val)
  266. // сам.temp.Set(val)
  267. // // сам.deltaOld = 0
  268. // сам.ВыстрелБлок().Сброс()
  269. // сам.isRepair.Сброс()
  270. // return
  271. // }
  272. // delta := сам.temp.Get() - val
  273. // // if delta > 0 { // Дельта будет больше нуля, если только
  274. // // if delta != сам.deltaOld {
  275. // // // log._rintf("INFO Health.setHealth(): потеря здоровья=%v/%v\n", -delta, val)
  276. // // сам.deltaOld = delta
  277. // // сам.temp.Set(val)
  278. // // }
  279. // // }
  280. // switch {
  281. // case сам.isEnd.Получ():
  282. // сам.temp.Set(0)
  283. // сам.isEnd.Уст()
  284. // сам.CancelBattle()
  285. // return
  286. // case val == 0:
  287. // сам.temp.Set(0)
  288. // сам.isEnd.Уст()
  289. // сам.CancelBattle()
  290. // return
  291. // case val <= 500: // Запретить стрельбу
  292. // сам.ВыстрелБлок().Уст() // Установить запрет стрельбы пока слабое здоровье
  293. // сам.isRepair.Уст()
  294. // // log._rintf("WARN Health.setHealth(): низкий уровень здоровья(%v)\n", val)
  295. // сам.Манёвр()
  296. // case val > 500: // Разрешить стрельбы
  297. // сам.ВыстрелБлок().Сброс()
  298. // сам.isRepair.Сброс()
  299. // if delta > сам.full.Get()*4/10 { // Проверить на критичность падения здоровья на 40%
  300. // // log._rintf("WARN Health.setHealth(): большая разовая потеря здоровья(%v)\n", delta)
  301. // сам.Манёвр()
  302. // сам.isRepair.Уст()
  303. // return
  304. // }
  305. // }
  306. // isMask := сам.ВыстрелБлок().Получ()
  307. // switch isMask {
  308. // case true:
  309. // // сам.countLow++
  310. // // if сам.countLow >= 200 {
  311. // // сам.isEnd.Уст()
  312. // // сам.CancelBattle()
  313. // // return
  314. // // }
  315. // default:
  316. // // сам.countLow = 0
  317. // }
  318. // if val == сам.full.Get() {
  319. // сам.temp.Set(val)
  320. // сам.isRepair.Сброс()
  321. // сам.ВыстрелБлок().Сброс()
  322. // // сам.countLow = 0
  323. // }
  324. // }