# Da Vinci Diamonds code review
!!! __не хватает header guard-ов pragma или ifndef__
!!! __класс GameHelper родительский, но не имеет ни одного виртуального метода - на что напарывается в BonusGame::GetCascadeSize()__
!! __BasicWheels/BonusWheels - полная копипаста, BasicGame/BonusGame - много копипасты. Возможно ли вынести общего предка?__
!! __CascadeWheelsHelper слишком большой и запутанный. Возможно ли повыносить методы/разбить на подклассы?__
! __В разметке непривычно видеть перемешанные Panel/Acion/Driver - привычнее сначала все Panel, потом все Action+Driver__
### BasicWheels:
1)
```cpp
BasicWheels::BasicWheels(cpp::count_ptr<CascadeWheelsHelper> wheels_helper)
{
m_cascade_wheels = wheels_helper;
}
```
используй лист инициализации: `: m_cascade_wheels(wheels_helper)`
2) вместо комментария можно вынести метод с этим же названием
```cpp
// Set gap size to center
for (auto wheel : m_wheels)
...
```
3) в некоторых случаях используешь `<algorithm>`, даже нестандартные как `std::none_of` - a в некоторых ручками - как
```cpp
for (auto wheel : new_symbols)
{
if (wheel.empty())
++m_stopped;
}
```
мелочь, но хотелось бы последовательности
4) так же субъективно показалось непоследовательным - `BasicWheels` и `BonusWheels` содержат в себе `CascadeWheelsHelper`, а `BasicGame` и `BonusGame` наследуются от `GameHelper`. Является ли игра `GameHelper`ом? (LSP)
### BigWinFeature
1) копипаста `BigWinFeature::ModelStateChanged` и `BigWinFeature::CounterStateChanged`
### BonusGame
1) при `dynamic_cast` полезно вставить `ASSERT` или `if(... != nullptr)`
```cpp
auto* cascade_wheels = dynamic_cast<BonusWheels*>(wheels.get());
cascade_wheels->StartCascade(m_destroy_series_symbols, new_symbols);
```
### BonusInBonus
1) есть метод `SetActionEndHandler`
```cpp
auto* action = vlib::ObjectFac::Instance()->LoadAction("fg.stars.explousions.fade.down");
action->SetEndHandler([this](cpp::count_ptr<gui::Action>) { Notify(SOUND_CUSTOM_EVENT.SET_VOLUME, 100); });
```
### CascadeWheelsHelper - cамый сложный файл
1)
```cpp
enum SymID
{
eWILD = 0,
eBONUS = 1,
eDIAMOND = 2,
eMONA_LISA = 3,
eFRANCHINUS_GAFFURIUS = 4,
eGINEVRA_DE_BENCI = 5,
ePURPLE_STOUNE = 6,
eGREEN_STOUNE = 7,
eORANGE_STOUNE = 8
};
```
STONE - опечатка. Цифры излишни, хотя перестраховаться - не страшно.
2) `Explosion_symbol` - название метода неформатированное, неинформативное, и сам метод огроменный
магические константы я бы вынес - типа `const gwc::Color ORANGE(255, 153, 51)`
3)
```cpp
const gwc::Time delay_symbol = vsdk::SlotCfg::Instance()->GetCutomData()["fakeCascadeConfig"]["delayBetweenSymbol"];
const gwc::Time delay_wheel = vsdk::SlotCfg::Instance()->GetCutomData()["fakeCascadeConfig"]["delayBetweenWheel"];
const gwc::Time duration_symbol_one_cell = vsdk::SlotCfg::Instance()->GetCutomData()["fakeCascadeConfig"]["durationSymbolOneCell"];
```
можно один раз достать json `CustomData`, избежать копипасты и лишней стены текста
( и можно отрефакторить имя `GetCuStomData()` )
4) в общем - файл и методы здоровенные
5) в нескольких местах такую конструкцию видел:
```cpp
std::string sound_name;
switch (sound_type)
{
case SoundType::eDROP_SMALL: sound_name = "drop_small"; break;
case SoundType::eDROP_MIDDLE: sound_name = "drop_middle"; break;
case SoundType::eDROP_LARGE: sound_name = "drop_large"; break;
case SoundType::eEXPLOSION_SMALL: sound_name = "expl_small"; break;
case SoundType::eEXPLOSION_MIDDLE: sound_name = "expl_middle"; break;
case SoundType::eEXPLOSION_LARGE: sound_name = "expl_large"; break;
default: break;
}
```
не проще ли вынести это в мапу, и доступаться по индексу? Так и лишнего синтаксиса switch не надо, и можно вынести данные от их обработки.
6) операторы можно соединять:
```cpp
figure_id = *new_symbol_id;
++new_symbol_id;
// figure_id = *new_symbol_id++
drop_from_pos.y = drop_from_pos.y - wheel->GetWheelView(-1)->GetSpan(gui::Axis::Y) * (new_cell_i_offset - 1);
// drop_from_pos.y -= ...
```
7) непоследовательность в переносах сигнатур методов
```cpp
CreateCascadeAction(
const cpp::count_ptr<vgui::VGUI_Panel>& view
, const gwc::Vec2& destination
, const gwc::Time& fall_time
, const gwc::Time& wait_time)
{
```
```cpp
void CascadeWheelsHelper::AdditionalSymbols
(
vlib::VLIB_WheelsView* wheels
, const std::vector<vcore::VCORE_Route::Position_t>& destroy_symbols
, const vcore::VCORE_Reels::Matrix_t& new_symbols
) {
```
### GameHelper
1) Копипаста
```cpp
bool GameHelper::IsLastCascade(const int cascade_number)
{
const int cascade_count = vcore::VCORE_Game::Instance()->Traits()->FruitTumbling()->GetCascadeSeries().size();
return cascade_number == cascade_count - 1;
}
const int GameHelper::GetCascadeSize()
{
return vcore::VCORE_Game::Instance()->Traits()->FruitTumbling()->GetCascadeSeries().size();
}
```
### RulesModel, GameShell, etc.
1) такие маленькие классы можно наверное сделать header-only. Или даже подумать собрать в один файл Helpers или что-то подобное.
### SeriesProcessor
1) унифицированно не лучше ли назвать SRModel?
2) избыточные условия
```cpp
if (score > 0)
{
if (mult >= win_small && mult < win_middle)
{
PLaySound(SoundType::eSMALL_WIN);
}
else if (mult >= win_middle && mult < win_large)
{
PLaySound(SoundType::eMIDDLE_WIN);
}
else if (mult >= win_large)
{
PLaySound(SoundType::eLARGE_WIN);
}
}
```
```cpp
if (score > 0)
{
if (mult < win_middle)
{
PLaySound(SoundType::eSMALL_WIN);
}
else if (mult < win_large)
{
PLaySound(SoundType::eMIDDLE_WIN);
}
else
{
PLaySound(SoundType::eLARGE_WIN);
}
}
```
должны ли проигрываться звуки при `mult < win_small` ? в нынешнем варианте - нет
### Разметка
1) можно ли избавиться от почти однострочных файлов - например markers_left, markers_right, move_button_spin?
как вариант, перенести их в app_plugin_decors