#pragma once #include "entity/material_mix.h" #include "core/materials.h" namespace ng { struct PotionSpray { double speed = 1, minimum = .5; bool bunch = false, skip_static = false, leak_gas = false; int count = 5; }; // 00bfdd10: one attempt per material, or throw_how_many on the initial press. // Velocities are pixels/second here; the GPU transport converts to pixels/tick. template int potion_spray(std::vector& parts, const MaterialDb& db, const PotionSpray& cfg, double capacity, double aim_x, double aim_y, double holder_vx, bool pressed, Random random, Emit emit) { if (capacity <= 0 || (cfg.bunch && !pressed)) return 0; int attempts = 0; for (auto& part : parts) { if (part.n <= 0 || (cfg.bunch && (int)part.n <= 0)) continue; const Material* m = db.find(part.mat); if (!m) continue; if (!cfg.bunch && cfg.skip_static && (m->type == CellType::Solid || (m->type == CellType::Liquid && attr_int(*m, "liquid_static", 0)))) continue; const double speed = cfg.speed * std::max(cfg.minimum, std::max(1, (int)part.n) / capacity); const int count = cfg.bunch ? std::max(0, cfg.count) : 1; for (int i = 0; i < count && part.n > 0; ++i) { const double angle = (random() * 2 - 1) * (cfg.bunch ? .25 : .05); const double c = std::cos(angle), s = std::sin(angle), length = std::hypot(aim_x, aim_y); double vx = length > 0 ? (aim_x * c - aim_y * s) / length * speed : 0; double vy = length > 0 ? (aim_x * s + aim_y * c) / length * speed : 0; vx += holder_vx; if (!cfg.bunch && cfg.leak_gas && m->type == CellType::Gas) { vx = 0; vy = -10; } emit(*m, vx, vy); part.n -= 1; // Native spends contents even when the particle pool is full. ++attempts; } } return attempts; } } // namespace ng