#pragma once // The contents of a flask or barrel: MaterialInventoryComponent holds how much of each material it has (count_per_material_type). A flask keeps its materials // apart (no reactions inside: do_reactions is 0 for potions), they react when they are poured out or spilled into the world. // Representation on the component: count_per_material_type.mix = "water:700;radioactive_liquid:300", plus the main material (the largest part) and the total count // under count_per_material_type.Material.material / .count (what scripts and the HUD read). #include #include #include #include #include #include "lua/entity_api.h" namespace ng { struct MixPart { std::string mat; double n = 0; }; inline std::vector mix_get(IEntityWorld& w, int comp) { std::vector parts; const LVal mix = w.get_value(comp, "count_per_material_type.mix", false); if (mix.t == LVal::T::Str && !mix.s.empty()) { size_t pos = 0; while (pos < mix.s.size()) { size_t end = mix.s.find(';', pos); if (end == std::string::npos) end = mix.s.size(); const std::string item = mix.s.substr(pos, end - pos); const size_t c = item.rfind(':'); if (c != std::string::npos) parts.push_back({item.substr(0, c), std::atof(item.c_str() + c + 1)}); pos = end + 1; } return parts; } const LVal m = w.get_value(comp, "count_per_material_type.Material.material", false), n = w.get_value(comp, "count_per_material_type.Material.count", false); if (m.t == LVal::T::Str && !m.s.empty() && n.t == LVal::T::Str && std::atof(n.s.c_str()) > 0) parts.push_back({m.s, std::atof(n.s.c_str())}); return parts; } inline double mix_total(const std::vector& p) { double t = 0; for (const MixPart& x : p) t += x.n; return t; } inline void mix_set(IEntityWorld& w, int comp, std::vector parts) { parts.erase(std::remove_if(parts.begin(), parts.end(), [](const MixPart& x) { return x.n < 0.5; }), parts.end()); std::stable_sort(parts.begin(), parts.end(), [](const MixPart& a, const MixPart& b) { return a.n > b.n; }); std::string s; for (const MixPart& x : parts) s += (s.empty() ? "" : ";") + x.mat + ":" + std::to_string((long long)std::llround(x.n)); w.set_value(comp, "count_per_material_type.mix", LVal::string(s)); w.set_value(comp, "count_per_material_type.Material.material", LVal::string(parts.empty() ? std::string() : parts.front().mat)); w.set_value(comp, "count_per_material_type.Material.count", LVal::string(std::to_string((long long)std::llround(mix_total(parts))))); } inline void mix_add(std::vector& parts, const std::string& mat, double n) { for (MixPart& x : parts) if (x.mat == mat) { x.n += n; return; } parts.push_back({mat, n}); } } // namespace ng