# Fishing Overview
Смотри так же [док для QA](https://docs.google.com/spreadsheets/d/1ZAuHqx96RNUt4_qTvZQJhSlsFUozh47F6sYDhmzMW1Y/edit#gid=0)
<br><br>
Каждая игра на клиенте имеет 3 основные части:
- package/Games/### (вся игровая логика)
- package/vcore (чисто взаимодействие с сервером, обращаемся из логики через синглтон)
- resources/### (конфигурационные файлы и разметка для правил/бонусов/ui)
Подробнее про каждую из них
### package/Games/###
#### AppPlugin
Отправная точка - AppPlugin. Каждая игра наследует `fishing_base::FishingBase_AppPlugin`.
Из него создаются инстансы переопределённых классов `Game`, `FishWorldManager`, `Rules`. (подробнее позже). В нём создаются и прикрепляются бонуски, оружие, пули, рыбы.
#### Builder/Handler
Для каждого типа игрового объекта (пули, рыбы) нужен `Builder`(задание ему эффектов появления/убийства/хита и т.д.) и `Handler`(что делать в определённых случаях: когда получил хит/столкнулся с краем экрана/дал выплату/получил крит и т.д.). Соответственно методы `AppPlugIn::PrepareGameFishHandlers` `AppPlugIn::PrepareGameFishBuilders` `AppPlugIn::PrepareGameBulletHandlers` `AppPlugIn::PrepareGameBulletBuilders`
Так же тут задаются билдеры для оружий.
Так же в `AppPlugIn::FinishPreparation` выполняются `AttachBonus` для независимых бонусок. Независимые - это не привязанные к пуле, например Pick'em.
Для всех бонусок в `AppPlugIn::PrepareBonusHandlers` возможно задать особые поведения. Так, например, чтобы задержать по таймеру начало бонуски, нужно добавить DelayedBonusHandler: `m_game->AddDelayedBonusHandler(BONUS_TYPE, new fishing_base::DelayedBonusHandler(MILLISECONDS));`
Подробнее каждый из бонусных хендлеров нужно исследовать в самом классе и его использовании в `FishingGame_Base`
В `fishing_base` есть большое количество уже определённых билдеров/хендлеров, поэтому если оружие/бонус/рыба просто копируется из предидущей игры - в `package/Games` достаточно просто корректно настроить AppPlugin.
Для новой логики смотри как переопределялись билдеры/хендлеры в прошлых играх (обычно в файлах `...BuildersCollection.hpp`, `...HandlersCollection.hpp`)
#### Оружия
разделяются на `GunWeapon` (то, что заменяет базовую пушку игрока - лазер, дрель и т.д.) и `ExtraWeapon` (то, что стреляет помимо базовой пушки - сюрикен, астероиды, лужи и т.д. Обычно у них ровно одна пуля)
Соответственно в `AppPlugin` нужно настроить `GunWeaponBuilder` и `ExtraWeaponBuilder`. В них самих задаётся соответствие пули к классу оружия.
Класс оружия в идеале просто содержит `VisualComponent`(непосредственно анимации) и `FireComponent`(коммуникация с сервером, таймеры перезарядки, логика создания пули и т.д.), и делегирует им. На практике границы логики часто размытые и некрасивые.
**ВАЖНО:** для ExtraWeapon нужно ОБЯЗАТЕЛЬНО переопределить метод `Clone()`.
#### Пули
разделяются на обычные(один раз залетела в рыбу, хитнула и удалилась) и LongLife(имеет большое кол-во хитов, может цеплять многих рыб, собирает их в группы и пачками отправляет на сервер, и удаляется только после использования всех хитов. Например дрель, лужа.)
Подробнее - смотри `FishingPlayer::ProcessHitForWeaponWithAccumulation` - сбор пака хитов и отправление на сервер; `LongLifeFireSystemWeaponComponent` и настройки для него `LongLifeFireSystemData_t` - FireComponent для LongLife пуль - тут логика таймеров перезарядки и обслуживание `m_bullet`
`gun_recover_timer` - начальная задержка до первой пули
`bullet_recover_timer` - период бездействия пули между отправкой одного хит пака на сервер и началом сбора другого
хит пак собирается либо до `concurrent_hits_qty` кол-ва хитов, либо время в `hits_pack_collecting_period`
#### FishWorldManager
кроме AppPlugin, есть несколько других основных классов, что переопределяются для каждой игры. Первый из них - FishWorldManager. Он больше и многозадачнее, чем хотелось бы. Он отвечает за все игровые объекты (m_game_world), попапы, таймлайны, реакцию на хиты/выплаты/убийства и другое.
Класс большой, но на практике для создания новой игры углубляться в него не нужно. Достаточно переопределить пару вещей: если в игре улучшеный `SoundManager` (что верно для всех последних рыб) - переопределить `BuildSoundManager`, задать маппинг `тип -> {анимация, звук}` для попапов в `BuildPopupManager`, фоновые звуки для боссов в `GetBigBossBackgroundSound`, и всякие специфичные штуки если они есть в игре. Например, если есть рыбы со стадиями (корабли в 402 или печеньки в 434) - переопределить `OnSpawnFish` по примеру.
#### FishingPlayer
Опять-таки очень большой класс, но на практике для новой игры не нужно глубоко копать.
Класс по большей части отвечает за оружия игрока, и за его деньги/ставку/UI.
Этот класс и для локальных игроков, и для врагов(regular player).
У Player есть gun_weapons_collection, extra_weapons_collection, которые являются шаблонами для пушек, в которые мы лезем при изменении оружия.
PetFish
Есть подобные классы PetPlayer/FishingPlayerWithPet - для этого ещё выделили общего родителя AbstractPlayer - сделано было для "Pet Fish" бонусок в 391 и 400, но это была неудачная идея.
Если в будущем понадобиться добавить PetFish - то всё рабочее, но вот модифицировать/развивать/усложнять - не рекоммендую. Для добавления PetFish достаточно главного Player в игре наследовать не от fishing_base::FishingPlayer, а fishing_base::FishingPlayerWithPet. По необходимости переопределить PetPlayer. Смотри по примерам ThunderFishing(391) и FishingThrones(400).
На практике
Вобщем, на практике, для FishingPlayer так же есть только пару методов переопределить в новой игре:
в `::Prepare()` добавить список кнопок из игры и какие события на них подвязаны. Это нужно для тестировочного режима AutoPlay, который активируется нажатием на кнопку FIRE в правом верхнем углу экрана. Здесь кнопки бонусного колеса, слот-машин и т.д.
в `::InitBonusWeaponsTypesCollection()` нужно задать коллекцию соответствий `{bonus, weapon}`
в `::IsWeaponWithHitsAccumulation` нужно задать список оружий с LongLife пулями.
Ну и дальше если есть специфичные фичи - например если есть буст - переопределить `BuildAimEffect`
если надо поменять цвет/расстояния в аиме - `GetAimLaserVisualData`
и т.д.
#### FishingGame
Как и вышеописанные классы, базовый класс большой и многозадачный, но на практике нужно только пару изменений.
`Game` отвечает за `Update` игры, вход/выход из бонусок, реакцию на получение инфы от сервера - `OnHit`, `OnFire`, `OnBonusQuantities`, и т.д.
На практике для новой игры достаточно переопределить `::BuildPlayer`, `::PrepareBonusGamesAccumulationVisual()` (маппинг маленьких круглых картинок, что вылетают из бонусных рыбок и летят в игрока и настройки стека отложенных бонусок)
`::InitPopupDisablingBonusesCollection()` - набор бонусок, во время которых нельзя показывать попапы
`::InitBonusesByStartupBehaviorTypes()` - распределение бонусок по категориям Мгновенные/Отложенные/Со своим стеком
Всё. Всё остальное - снова - посмотеть если для некоторых специфичных вещей нужно что-то переопределять.
#### Итог
Ещё раз: основные классы `AppPlugin`, `FishWorldManager`, `FishingPlayer`, `Game`. В `fishing_base` они объёмные. Но для практического описания новой игры достаточно нескольких переопределённых методов. И *ОБЯЗАТЕЛЬНО* если копируется оружие/бонуска/рыба из предидущей игры - посмотреть нет ли в этих классах особой логики с ней связанных.
#### Типы бонусок
Бонуски можно разделить по разным признакам.
По типу запуска:
1) МГНОВЕННЫЕ - начинаются сразу при выбивании рыбки, не смотря играют ли другие бонусы или нет. Примеры: сюрикен, бомба, астероиды.
2) ОТЛОЖЕННЫЕ - при выбивании рыбы не начинаются, если уже запущены другие ОТЛОЖЕННЫЕ бонуски. Пример: лазер и дрель. Если выбиваешь дрель лазером, то она летит в очередь. Запустится только по окончанию лазера.
3) СО СВОИМ СТЕКОМ - начинаются сразу, вне зависимости от ОТЛОЖЕННЫХ бонусок. Единственное исключение - когда уже играет бонуска ТАКОГО ЖЕ ТИПА. Пример: Multiplier Fish. Первая выбитая начнёт крутиться сразу же, вне зависимости от лазеров/сюрикенов/и т.д. Но если на поле крутится другая Multiplier Fish - то эта пойдёт в отдельную очередь.
По наличии пули:
1) Independent бонуски - без пули. Пример: слот-машина, пикем, колесо, MultiplierFish.
2) Обычная - с пулей. Пример: лазер, дрель, бомба, астероиды.
Стоит заметить, что обычные бонуски не описываются отдельно, достаточно указать маппинги типов бонусок к пулям, оружию. Independent бонуски описываются отдельными классами, наследниками AbstractIndependentBonus.
Independent не отображаются врагам, но есть система оповещений-попапчиков. Смотри "enemyBonusStateVisualData" в fishing_cfg.json, классы `EnemyBonusesManager` `AbstractEnemyBonusProcessor`, методы `BuildBonusEnemyPopupStartInformMessage()`, `BuildBonusEnemyPopupEndInformMessage()`.
### package/vcore
Часть для коммуникации с сервером.
Самое главное - создать `vcore\include\fishing\services\NAME_types.hpp` в котором определяются id бонусов, пуль и рыб. ID отсюда используются во всём проекте. Важно убедиться что id совпадают с сервером.
Плюс создать `VCORE_NAMEType` и наследника `VCORE_NAMEImpl` - смотри по аналогии с предидущими рыбами. Важно добавить проверку на адекватность, если данные связаны с артом. Напрмер, на колесе нарисовано "х100", а сервер присылает сектор - важно убедиться что они совпадают.
### resources/###/visual
Обратить внимание, что существует папка `resources/FishingCommon` с универсальными ресурсами, доступными каждой игре. При необходимости их можно переопределять в папке с номером игры. Например, если `app_plugin_decors.xml` будет и там и там, в игре будет использоваться тот из папки с номером игры.
#### Основные файлы:
`app_plugin_decors.xml` - все слои игры: фон, пули, рыбы и т.д. Здесь обычно просят поменять чтобы "те символы плавали выше тех" или что-то такое.
`app_plugin_wheels.xml` - бонусные слои и попапы. Обычно Independent бонуски имеют тут панель parent, и соответственно драйверы для показания/скрытия. Так же здесь обычно SpineView со всеми попапами.
`bodies.json` - маппинг `{body_id -> shape_id}`, то есть соответствие body к коллайдеру, описанному в `shapes.json`. Несколько рыб (например все бонусные шары) могут иметь один коллайдер.
`bullet_sound.json`, `fish_sound.json`- для каждого объекта можно задать звуки startSound = появления, lifeSound = залупленый звук жизни, deathSound = звук пропадения неубитого объекта, killSound = звук убийства объекта
`bullet_visualization.json` - визуал, что накладывается на пулю. Это может быть картинка `imageName` мувик `movieName` или спайн `spineData` - тут набор `{spine_name, spine_anim_idle, [spine_anim_start], [spine_anim_end]}` при чём последние два - опциональные. Для невидимых можно указать `"imageName" : "transparent_pixel"`
`bullets.json`, `fishes.json` - маппинг `{GDD_id -> body}`. Именно здесь можно отключить поворот для объектов (напрмер боссов или бонусных символов): `"rotationEnabled": true`
`enemy_bonuses_visual_spine_data.xml` - спайн данные для мини попапов соперников
`extra_path_collection.json` - коллекция путей для пуль - используется например в сюрикенах
`fish_visualization.json` - визуальные элементы рыб: картинка/мувик/спайн, тень, монетки что выпадают.
`fishing_cfg.json` - аналог `slot_cfg` - так же есть возможность дописывать "customData" и доступаться из любого места через `FishingCfg::Instance()`
`fishing_sounds.xml` - набор базовых звуков - аим, буст, кнопки, лобби и т.д. Особо нечего менять.
`killing_spree_data.json` - настройки фичи KillingSpree (звуки за набранные очки) - настраивает геймдиз.
`longlife_bullets_damage_setttings.json` - сколько хитов наносят LongLife пули по специфичным рыбам - настраивает геймдиз
`players_bullets_panel` - UI пушек игрока. Здесь расписать спайн gun и перепроверить позиции.
`rl_*` - правила. Верстает tech art.
`shapes.json` - коллайдеры, заданы в виде набора кругов.
`sound_groups_cfg.json` - здесь нужно все звуки из папки sounds разбить на категории. Обычно это бекграунда/обычные/войсоверы.
`timeline_visualization.json` - настройки таймлайнов, настраиваются геймдизом.
`weapon_guns_sound.json` - коллекции звуков, из которых на каждый выстрел выбирается случайный
`weapon_guns_visualization.json` - аналог fish_visualization, но для пушек.
так же в этой папке для Independent бонусок создаются отдельные `.xml`
## Создание базовой игры
- создать наследника `fishing_base::AppPlugin`
- создать метод `create_plugin_NAME()`, смотри `GamesFactory.hpp`.
- добавить игру в `GShell/SupportedGames.cpp`, `VCORE_FishingGame` `VCORE_GameId`
- создать класс `FishingGame` и переопределить метод `AppPlugin::BuildFishingGame()`
- добавить иконку игры - любую картинку - `resources/GameIconsRiver/images`
- добавить готовые ресурсы - фоны, рыбы, базовые пули
- настроить конфигурационные файлы `resources/###/visual` (подробности выше)
- договориться, чтобы на каком-то сервере собрали игру и поставили базовый таймлайн, указать этот сервер+бренд в Settings.ini
В конечном результате мы должны получить игру, которая запускается, можно зайти за стол, увидеть на таймлайне доступные символы поточной игры, можно было пострелять базовой пушкой и получить обработку хита обычных рыб.
Дальше переопределять `FishWorldManager`, `Game`, `Player`, во `vcore` указать список id бонусок/рыб/пуль, и создать имплементацию `FishingGameImpl`.
Во всех этапах смотреть на предидущие игры для примера.
Дальше добавлять бонуски по очереди, стартуя в AppPlugin.
## Разное
- У игрового стола есть ориентации: северная и южная (смотри класс `fishing_base::OrientationAdapter`). Важно следить, что координаты для рассчётов (что не выводится на экран, коллайдеры например) определяются глобально, независимо от ориентации. А вот в визуальных эффектах (всё, что рисуется на экран), сначала нужно преобразовать координаты в локальные (смотри `OrientationAdapter::TransformToLocal(pos)`)
- Неудачные фичи, которые лучше не переиспользовать:
-- Лава и бомба из 391 - они теряли хиты.
-- Пет фиш из 391, 400 - только рескин. Добавление новой логики туго.
-- Дрель из 434 - сложно и некрасиво.
- Выгодно выносить отдельно файл с коммандами Notify в cmd, все настройки оружий в WeaponCfg, все кастомные типы в types. Выгодно разбивать на отдельные подпапки бонуски, оружия, компоненты.
- В кратце про фичи
-- KillingSpree = за каждую рыбу начисляются очки, и потом войсовер (типа "Rampage", "Ultra Kill")
-- MixerSoundManager = продвинутая система звуков, которая разбивает их на группы и приглушает менее важные
-- Stickers = эмоджи внутри игры, используют BroadcastMessage
-- Tutorial = в самый первый заход отображается обучалка. Потом записывается в preferences.enс флажок, что больше не нужно.
-- FishWash = смывка, когда таймлайн подходит к концу - рыбы уплывают быстрее
-- FishRush = таймлайн, который отличается только путями рыб и их скоростью
-- MonsterHunt = таймлайн, в котором рыбы увеличены в 2 раза
-- Boost = двойная пушка для обычного и аимного режимов. Обратите внимание, что это всё одна пуля со ставкой одинарной, просто у неё в 2 раза больше шанс выбить. Все бонуски/множители считаются от ОДИНАРНОЙ ставки, даже если были выбиты бустом.
-- SquigglyFish = рыбы с нестатичными, но двигающимися коллайдерами, которые привязываются к спайну. Смотри BossWorm из 434. Им задаются определённые маршруты и маппинг в fishing_cfg.
-- BilliardsPos = восстановление положения пуль, которые летают по прямой и отбиваются от краёв. Смотри [Arithmetic billiards](https://en.wikipedia.org/wiki/Arithmetic_billiards).