#include "Fish.h" #include "Aquarium.h" #include "Random.h" #include "assets/FishAssets.h" #include "defs.h" std::unordered_map Fish::color_map; Fish::Fish() : Fish(getRandomAssetIndex()) {} Fish::Fish(int asset_index) : Entity(), image(fishAssetPairs[asset_index].image), mask(fishAssetPairs[asset_index].mask), speed(Random::floatInRange(0.25f, 2.25f)), moving_right(asset_index % 2 == 0) { const auto &aquarium = Aquarium::getInstance(); y = Random::intInRange(static_cast(image.size()) + 6, aquarium.getHeight() - static_cast(image.size())); x = moving_right ? -20.0f : static_cast(aquarium.getWidth()); randomizeMask(); } void Fish::randomizeMask() { // Clear and rebuild color map with fresh random colors each time color_map.clear(); color_map['4'] = 'W'; // White is always '4' // Assign random colors to digits 1-3, 5-9 for (char digit = '1'; digit <= '9'; ++digit) { if (digit != '4') { color_map[digit] = AVAILABLE_COLORS[Random::intInRange( 0, static_cast(AVAILABLE_COLORS.size()) - 1)]; } } // Apply color mapping to mask for (auto &line : mask) { for (char &ch : line) { if (auto it = color_map.find(ch); it != color_map.end()) { ch = it->second; } } } } int Fish::getRandomAssetIndex() { return Random::intInRange(0, static_cast(fishAssetPairs.size()) - 1); } void Fish::update() noexcept { x += moving_right ? speed : -speed; } bool Fish::shouldBeRemoved() const noexcept { const auto &aquarium = Aquarium::getInstance(); if (moving_right) { return x > static_cast(aquarium.getWidth()); } else { return (x + static_cast(image[0].length())) < 0; } } std::unique_ptr Fish::createReplacement() const { return std::make_unique(); } int Fish::getPreferredLayer() const noexcept { return 10; } bool Fish::shouldSpawnBubble() const { return Random::floatInRange(0, 1) < BUBBLE_SPAWN_CHANCE; }