# 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).